import pbxPool from "./pbx-pool";

export interface PbxExtension {
  id: string;
  extension: string;
  name: string;
  mohClassId: string | null;
}

export interface PbxFollowMe {
  id: string;
  isEnabled: boolean;
  ringTime: number;
  numbers: Array<{
    id: string;
    number: string;
    ringDelay: number;
    orderNum: number;
  }>;
}

export interface PbxVoicemailBox {
  id: string;
  mailbox: string;
  email: string | null;
  emailNotify: boolean;
  attachVoicemail: boolean;
  newMessages: number;
}

export interface PbxMohClass {
  id: string;
  name: string;
  isDefault: boolean;
}

/**
 * Get extension for a user by their gsc_core user ID (matches pbx_extensions.user_id).
 */
export async function getUserExtension(userId: string, tenantId: string): Promise<PbxExtension | null> {
  const result = await pbxPool.query(
    `SELECT e.id, e.extension, e.name, e.metadata
     FROM pbx_extensions e
     WHERE e.user_id = $1 AND e.tenant_id = $2 AND e.is_active = true
     LIMIT 1`,
    [userId, tenantId]
  );
  if (result.rows.length === 0) return null;
  const row = result.rows[0];
  // MOH class ID may be stored in extension metadata
  const meta = row.metadata as Record<string, unknown> | null;
  return {
    id: row.id,
    extension: row.extension,
    name: row.name,
    mohClassId: (meta?.moh_class_id as string) || null,
  };
}

/**
 * Get follow-me (call forwarding) config for an extension.
 */
export async function getFollowMe(extensionId: string): Promise<PbxFollowMe | null> {
  const fmResult = await pbxPool.query(
    `SELECT id, is_enabled, ring_time
     FROM pbx_follow_me
     WHERE extension_id = $1
     LIMIT 1`,
    [extensionId]
  );
  if (fmResult.rows.length === 0) return null;
  const fm = fmResult.rows[0];

  const numResult = await pbxPool.query(
    `SELECT id, number, ring_time, order_num
     FROM pbx_follow_me_numbers
     WHERE follow_me_id = $1
     ORDER BY order_num ASC`,
    [fm.id]
  );

  return {
    id: fm.id,
    isEnabled: fm.is_enabled,
    ringTime: fm.ring_time,
    numbers: numResult.rows.map((r) => ({
      id: r.id,
      number: r.number,
      ringDelay: r.ring_time,
      orderNum: r.order_num,
    })),
  };
}

/**
 * Get voicemail box for an extension.
 */
export async function getVoicemailBox(extensionId: string): Promise<PbxVoicemailBox | null> {
  const result = await pbxPool.query(
    `SELECT id, mailbox, email, mwi_enabled, email_attachment, new_messages
     FROM pbx_voicemail_boxes
     WHERE extension_id = $1 AND is_active = true
     LIMIT 1`,
    [extensionId]
  );
  if (result.rows.length === 0) return null;
  const row = result.rows[0];
  return {
    id: row.id,
    mailbox: row.mailbox,
    email: row.email,
    emailNotify: row.mwi_enabled ?? true,
    attachVoicemail: row.email_attachment ?? true,
    newMessages: row.new_messages ?? 0,
  };
}

/**
 * Get music-on-hold classes for a tenant.
 */
export async function getMohClasses(tenantId: string): Promise<PbxMohClass[]> {
  const result = await pbxPool.query(
    `SELECT id, name, is_default
     FROM pbx_moh_classes
     WHERE tenant_id = $1 AND is_active = true
     ORDER BY name ASC`,
    [tenantId]
  );
  return result.rows.map((r) => ({
    id: r.id,
    name: r.name,
    isDefault: r.is_default,
  }));
}

/**
 * Upsert follow-me configuration.
 */
export async function upsertFollowMe(
  extensionId: string,
  data: { isEnabled: boolean; ringTime: number; numbers: Array<{ number: string; ringDelay: number; orderNum: number }> }
) {
  const client = await pbxPool.connect();
  try {
    await client.query("BEGIN");

    const fmResult = await client.query(
      `INSERT INTO pbx_follow_me (extension_id, is_enabled, ring_time)
       VALUES ($1, $2, $3)
       ON CONFLICT (extension_id) DO UPDATE SET is_enabled = $2, ring_time = $3, updated_at = NOW()
       RETURNING id`,
      [extensionId, data.isEnabled, data.ringTime]
    );
    const followMeId = fmResult.rows[0].id;

    await client.query("DELETE FROM pbx_follow_me_numbers WHERE follow_me_id = $1", [followMeId]);
    for (const num of data.numbers) {
      await client.query(
        `INSERT INTO pbx_follow_me_numbers (follow_me_id, number, ring_time, order_num)
         VALUES ($1, $2, $3, $4)`,
        [followMeId, num.number, num.ringDelay, num.orderNum]
      );
    }

    await client.query("COMMIT");
  } catch (err) {
    await client.query("ROLLBACK");
    throw err;
  } finally {
    client.release();
  }
}

/**
 * Update extension metadata (e.g., MOH class).
 */
export async function updateExtension(
  tenantId: string,
  extensionId: string,
  data: { mohClassId?: string | null }
) {
  if (data.mohClassId !== undefined) {
    // Store MOH class ID in extension metadata
    await pbxPool.query(
      `UPDATE pbx_extensions
       SET metadata = jsonb_set(COALESCE(metadata, '{}'), '{moh_class_id}', $1::jsonb),
           updated_at = NOW()
       WHERE tenant_id = $2 AND id = $3`,
      [JSON.stringify(data.mohClassId), tenantId, extensionId]
    );
  }
}

/**
 * Update voicemail box settings.
 */
export async function updateVoicemailBox(
  tenantId: string,
  voicemailBoxId: string,
  data: { email?: string | null; emailNotify?: boolean; attachVoicemail?: boolean; pin?: string }
) {
  const sets: string[] = [];
  const params: unknown[] = [];
  let idx = 1;

  if (data.email !== undefined) {
    sets.push(`email = $${idx++}`);
    params.push(data.email);
  }
  if (data.emailNotify !== undefined) {
    sets.push(`mwi_enabled = $${idx++}`);
    params.push(data.emailNotify);
  }
  if (data.attachVoicemail !== undefined) {
    sets.push(`email_attachment = $${idx++}`);
    params.push(data.attachVoicemail);
  }
  if (data.pin) {
    sets.push(`pin_encrypted = $${idx++}`);
    params.push(data.pin);
  }

  if (sets.length === 0) return;

  sets.push(`updated_at = NOW()`);
  params.push(voicemailBoxId);

  await pbxPool.query(
    `UPDATE pbx_voicemail_boxes SET ${sets.join(", ")} WHERE id = $${idx}`,
    params
  );
}
