import type { McpToolCaller } from "./mcp-tool-client.ts";

export interface AiSchedulingProvisioningInput {
  admin: McpToolCaller;
  extensionNumber?: string;
  extensionName?: string;
  email?: string;
  deviceName?: string;
}

export interface AiSchedulingProvisioningPlan {
  ok: boolean;
  desired: Required<Omit<AiSchedulingProvisioningInput, "admin">>;
  existingExtension?: RingCentralExtensionSummary;
  extensionNumberAvailable: boolean;
  auth?: RingCentralAuthSummary;
  canUseApiForExtensionCreate: boolean;
  approvalText: string;
  actions: Array<{
    kind: "ringcentral_write" | "manual_admin_console";
    description: string;
    endpoint?: string;
    body?: Record<string, unknown>;
  }>;
  blockers: string[];
}

export interface AiSchedulingProvisioningExecution {
  ok: boolean;
  dryRun: boolean;
  plan: AiSchedulingProvisioningPlan;
  result?: unknown;
}

interface RingCentralExtensionSummary {
  id: string;
  extensionNumber?: string;
  name?: string;
  type?: string;
  status?: string;
}

interface RingCentralAuthSummary {
  scopes: string[];
  hasEditAccounts: boolean;
  hasEditExtensions: boolean;
}

export async function buildAiSchedulingProvisioningPlan(
  input: AiSchedulingProvisioningInput,
): Promise<AiSchedulingProvisioningPlan> {
  const desired = {
    extensionNumber: input.extensionNumber ?? "9001",
    extensionName: input.extensionName ?? "AI Scheduling Backup",
    email: input.email ?? "agent@exulthealthcare.com",
    deviceName: input.deviceName ?? "AI Scheduling Backup SIP",
  };
  const extensions = await listExtensionSummaries(input.admin);
  const existingExtension = extensions.find(
    (extension) =>
      extension.extensionNumber === desired.extensionNumber ||
      normalize(extension.name) === normalize(desired.extensionName),
  );
  const auth = await authSummary(input.admin);
  const blockers: string[] = [];

  if (existingExtension && existingExtension.name !== desired.extensionName) {
    blockers.push(
      `Extension number ${desired.extensionNumber} is already used by ${existingExtension.name ?? existingExtension.id}.`,
    );
  }
  if (!auth.hasEditAccounts) {
    blockers.push("Current RingCentral JWT app does not advertise EditAccounts scope.");
  }

  return {
    ok: blockers.length === 0,
    desired,
    existingExtension,
    extensionNumberAvailable: !existingExtension,
    auth,
    canUseApiForExtensionCreate: auth.hasEditAccounts,
    approvalText: approvalText(desired),
    actions: [
      {
        kind: "ringcentral_write",
        description: `Create enabled User extension ${desired.extensionNumber} named ${desired.extensionName}.`,
        endpoint: "POST /restapi/v1.0/account/~/extension",
        body: {
          contact: {
            firstName: "AI Scheduling",
            lastName: "Backup",
            email: desired.email,
          },
          extensionNumber: desired.extensionNumber,
          status: "Enabled",
          type: "User",
        },
      },
      {
        kind: "manual_admin_console",
        description:
          "Add an Existing Phone / Other Phone device under the new extension, then use sip:discover to read SIP info.",
      },
    ],
    blockers,
  };
}

export async function executeAiSchedulingExtensionProvisioning(input: {
  admin: McpToolCaller;
  approvalText: string;
  execute: boolean;
  extensionNumber?: string;
  extensionName?: string;
  email?: string;
  deviceName?: string;
}): Promise<AiSchedulingProvisioningExecution> {
  const plan = await buildAiSchedulingProvisioningPlan(input);
  if (!plan.ok) {
    return { ok: false, dryRun: !input.execute, plan };
  }
  if (input.approvalText !== plan.approvalText) {
    return {
      ok: false,
      dryRun: !input.execute,
      plan: {
        ...plan,
        blockers: ["Provided approval text does not exactly match the checked plan."],
      },
    };
  }

  const result = await input.admin.callTool("create_ai_scheduling_extension", {
    approval_text: input.approvalText,
    dry_run: !input.execute,
  });
  return {
    ok: !isErrorPayload(result),
    dryRun: !input.execute,
    plan,
    result,
  };
}

async function listExtensionSummaries(admin: McpToolCaller): Promise<RingCentralExtensionSummary[]> {
  const result = (await admin.callTool("list_extensions")) as {
    records?: Array<Record<string, unknown>>;
  };
  return (result.records ?? []).map((extension) => ({
    id: String(extension.id),
    extensionNumber: stringValue(extension.extensionNumber),
    name: stringValue(extension.name),
    type: stringValue(extension.type),
    status: stringValue(extension.status),
  }));
}

async function authSummary(admin: McpToolCaller): Promise<RingCentralAuthSummary> {
  const result = (await admin.callTool("get_auth_context")) as Record<string, unknown>;
  const scopes = Array.isArray(result.scopes)
    ? result.scopes.filter((scope): scope is string => typeof scope === "string")
    : typeof result.scope === "string"
      ? result.scope.split(/\s+/).filter(Boolean)
      : [];
  return {
    scopes,
    hasEditAccounts: result.has_edit_accounts === true || scopes.includes("EditAccounts"),
    hasEditExtensions: result.has_edit_extensions === true || scopes.includes("EditExtensions"),
  };
}

function approvalText(input: Required<Omit<AiSchedulingProvisioningInput, "admin">>): string {
  return [
    "Approve these RingCentral writes only:",
    `1. Create a new enabled RingCentral extension named '${input.extensionName}', extension number '${input.extensionNumber}', using '${input.email}' if RingCentral requires an email, with no direct phone number assignment.`,
    `2. Add one Existing Phone / Other Phone device under extension '${input.extensionNumber}', named '${input.deviceName}', for Cloud Phone SDK SIP registration.`,
    "3. Do not change queue 55, IVR 2000, after-hours routing, greetings, forwarding, caller ID, or phone-number assignments.",
  ].join("\n");
}

function normalize(value: string | undefined): string {
  return (value ?? "").trim().toLowerCase();
}

function stringValue(value: unknown): string | undefined {
  return typeof value === "string" && value.trim() ? value.trim() : undefined;
}

function isErrorPayload(value: unknown): boolean {
  return Boolean(
    value &&
      typeof value === "object" &&
      !Array.isArray(value) &&
      (value as { error?: unknown }).error,
  );
}
