import { z } from 'zod';
import { BasePack } from '../base-pack.js';
import type { TwilioClient } from '../../client.js';
import * as renderer from '../../apps/renderer.js';

export class ContactCenterPack extends BasePack {
  readonly name = 'contact-center';
  readonly description = 'TaskRouter for call center management — workspaces, queues, agents, routing';
  readonly keywords = ['taskrouter', 'queue', 'agent', 'worker', 'routing', 'call center', 'contact center'];

  constructor(client: TwilioClient) {
    super(client);
  }

  setup(): void {
    // ─── twilio_contact_center_setup ───
    this.registerTool({
      name: 'twilio_contact_center_setup',
      description: 'Set up a complete TaskRouter workspace with queues and agents. Creates workspace, activities, queues with routing filters, and workers with skills.',
      category: 'contact-center',
      safety: 'yellow',
      tier: 2,
      isApp: true,
      annotations: { costHint: false },
      inputSchema: z.object({
        name: z.string().describe('Workspace friendly name'),
        queues: z.array(z.object({
          name: z.string().describe('Queue name'),
          target_workers: z.string().optional().describe('TaskRouter filter expression (e.g., "skills HAS \'sales\'")'),
        })).describe('Task queues to create'),
        agents: z.array(z.object({
          name: z.string().describe('Agent/worker name'),
          phone: z.string().optional().describe('Agent phone number'),
          skills: z.array(z.string()).optional().describe('Agent skills/capabilities'),
          activity: z.string().optional().describe('Initial activity (Available, Unavailable, Break, Offline)'),
        })).describe('Agents/workers to create'),
      }),
      _meta: {
        labels: {
          category: "contact-center",
          access: "read",
          complexity: "simple"
        }
      },
      handler: async (params) => {
        try {
          // Create workspace
          const workspace = await this.client.execute(c =>
            c.taskrouter.v1.workspaces.create({
              friendlyName: params.name,
              template: 'NONE',
            })
          );

          // Create standard activities
          const activities = await Promise.all([
            this.client.execute(c => c.taskrouter.v1.workspaces(workspace.sid).activities.create({
              friendlyName: 'Available',
              available: true,
            })),
            this.client.execute(c => c.taskrouter.v1.workspaces(workspace.sid).activities.create({
              friendlyName: 'Unavailable',
              available: false,
            })),
            this.client.execute(c => c.taskrouter.v1.workspaces(workspace.sid).activities.create({
              friendlyName: 'Break',
              available: false,
            })),
            this.client.execute(c => c.taskrouter.v1.workspaces(workspace.sid).activities.create({
              friendlyName: 'Offline',
              available: false,
            })),
          ]);

          const activityMap = new Map(activities.map(a => [a.friendlyName, a.sid]));

          // Create task queues
          const queues = await Promise.all(
            params.queues.map((q: { name: string; target_workers?: string }) =>
              this.client.execute(c => c.taskrouter.v1.workspaces(workspace.sid).taskQueues.create({
                friendlyName: q.name,
                targetWorkers: q.target_workers || '1==1', // Default: all workers
                reservationActivitySid: activityMap.get('Available'),
                assignmentActivitySid: activityMap.get('Available'),
              }))
            )
          );

          // Create workers
          const workers = await Promise.all(
            params.agents.map((agent: { name: string; phone?: string; skills?: string[]; activity?: string }) => {
              const attributes: any = {
                contact_uri: agent.phone || '',
                skills: agent.skills || [],
              };
              
              const activityName = agent.activity || 'Offline';
              const activitySid = activityMap.get(activityName) || activityMap.get('Offline');

              return this.client.execute(c => c.taskrouter.v1.workspaces(workspace.sid).workers.create({
                friendlyName: agent.name,
                attributes: JSON.stringify(attributes),
                activitySid,
              }));
            })
          );

          // Build org chart app
          const html = renderer.appLayout(
            '🏢 Contact Center Setup',
            `Workspace: ${params.name} (${workspace.sid})`,
            `
            <div class="card">
              <div class="card-header">📊 Overview</div>
              <div class="card-grid card-grid-3" style="margin-top: 8px;">
                ${renderer.metricCard(String(queues.length), 'Queues')}
                ${renderer.metricCard(String(workers.length), 'Agents')}
                ${renderer.metricCard(String(activities.length), 'Activities')}
              </div>
            </div>

            <div class="card">
              <div class="card-header">📋 Queues</div>
              ${renderer.table(
                ['Queue', 'Target Workers', 'Status'],
                queues.map(q => [
                  `<strong>${q.friendlyName}</strong>`,
                  params.queues.find((pq: { name: string; target_workers?: string }) => pq.name === q.friendlyName)?.target_workers || 'All',
                  renderer.badge('Active', 'success'),
                ])
              )}
            </div>

            <div class="card">
              <div class="card-header">👥 Agents</div>
              ${renderer.table(
                ['Name', 'Status', 'Skills', 'Contact'],
                workers.map((w, i) => {
                  const agent = params.agents[i];
                  const activityName = agent.activity || 'Offline';
                  const activityColor = activityName === 'Available' ? 'success' : activityName === 'Break' ? 'warning' : 'muted';
                  const skills = agent.skills || [];
                  
                  return [
                    `<strong>${w.friendlyName}</strong>`,
                    renderer.badge(activityName, activityColor as any),
                    skills.length > 0 ? skills.map((s: string) => renderer.badge(s, 'info')).join(' ') : '—',
                    agent.phone || '—',
                  ];
                })
              )}
            </div>
            `
          );

          return this.appResult(html,
            `Contact Center created!\n` +
            `Workspace: ${workspace.sid}\n` +
            `Queues: ${queues.length}\n` +
            `Agents: ${workers.length}\n` +
            `Activities: ${activities.map(a => a.friendlyName).join(', ')}`
          );
        } catch (err: any) {
          return this.errorResult(`Failed to setup contact center: ${err.message}`);
        }
      },
    });

    // ─── twilio_agent_status ───
    this.registerTool({
      name: 'twilio_agent_status',
      description: 'View all agents in a workspace with their current status and capabilities.',
      category: 'contact-center',
      safety: 'green',
      tier: 2,
      isApp: true,
      annotations: { readOnlyHint: true },
      inputSchema: z.object({
        workspace_sid: z.string().describe('TaskRouter workspace SID'),
      }),
      _meta: {
        labels: {
          category: "contact-center",
          access: "read",
          complexity: "simple"
        }
      },
      handler: async (params) => {
        try {
          // Fetch workers
          const workers = await this.client.execute(c =>
            c.taskrouter.v1.workspaces(params.workspace_sid).workers.list({ limit: 100 })
          );

          // Fetch activities to resolve names
          const activities = await this.client.execute(c =>
            c.taskrouter.v1.workspaces(params.workspace_sid).activities.list()
          );
          const activityMap = new Map(activities.map(a => [a.sid, a.friendlyName]));

          // Build agent grid
          const agentCards = workers.map(w => {
            const attributes = JSON.parse(w.attributes || '{}');
            const skills = attributes.skills || [];
            const activityName = activityMap.get(w.activitySid) || 'Unknown';
            
            let activityColor: 'green' | 'yellow' | 'red' | 'gray' = 'gray';
            if (activityName === 'Available') activityColor = 'green';
            else if (activityName === 'Break') activityColor = 'yellow';
            else if (activityName === 'Offline') activityColor = 'gray';

            const skillsBadges = skills.length > 0 
              ? skills.map((s: string) => renderer.badge(s, 'info')).join(' ')
              : '<span class="muted">No skills</span>';

            return `
              <div class="card">
                <div style="display: flex; justify-content: space-between; align-items: start; margin-bottom: 8px;">
                  <strong>${w.friendlyName}</strong>
                  ${renderer.statusDot(activityColor)}${renderer.badge(activityName, activityColor === 'green' ? 'success' : activityColor === 'yellow' ? 'warning' : 'muted')}
                </div>
                <div class="small muted">Skills:</div>
                <div style="margin-top: 4px;">${skillsBadges}</div>
                <div class="small muted" style="margin-top: 8px;">${w.sid}</div>
              </div>
            `;
          }).join('');

          const html = renderer.appLayout(
            '👥 Agent Status',
            `Workspace: ${params.workspace_sid}`,
            `
            <div class="card">
              <div class="card-header">📊 Summary</div>
              <div class="card-grid card-grid-4" style="margin-top: 8px;">
                ${renderer.metricCard(String(workers.length), 'Total Agents')}
                ${renderer.metricCard(String(workers.filter(w => activityMap.get(w.activitySid) === 'Available').length), 'Available')}
                ${renderer.metricCard(String(workers.filter(w => activityMap.get(w.activitySid) === 'Break').length), 'On Break')}
                ${renderer.metricCard(String(workers.filter(w => activityMap.get(w.activitySid) === 'Offline').length), 'Offline')}
              </div>
            </div>

            <div class="card-grid card-grid-3">
              ${agentCards}
            </div>
            `
          );

          return this.appResult(html,
            `Agent Status:\n` +
            workers.map(w => {
              const activityName = activityMap.get(w.activitySid) || 'Unknown';
              const attributes = JSON.parse(w.attributes || '{}');
              const skills = attributes.skills || [];
              return `  ${w.friendlyName}: ${activityName} (${skills.join(', ') || 'no skills'})`;
            }).join('\n')
          );
        } catch (err: any) {
          return this.errorResult(`Failed to fetch agent status: ${err.message}`);
        }
      },
    });

    // ─── twilio_queue_manager ───
    this.registerTool({
      name: 'twilio_queue_manager',
      description: 'View task queue statistics — tasks in queue, wait times, available agents.',
      category: 'contact-center',
      safety: 'green',
      tier: 2,
      isApp: true,
      annotations: { readOnlyHint: true },
      inputSchema: z.object({
        workspace_sid: z.string().describe('TaskRouter workspace SID'),
      }),
      _meta: {
        labels: {
          category: "contact-center",
          access: "read",
          complexity: "simple"
        }
      },
      handler: async (params) => {
        try {
          // Fetch task queues
          const queues = await this.client.execute(c =>
            c.taskrouter.v1.workspaces(params.workspace_sid).taskQueues.list({ limit: 100 })
          );

          // Fetch statistics for each queue
          const queueStats = await Promise.all(
            queues.map(async q => {
              try {
                const stats: any = await this.client.execute(c =>
                  c.taskrouter.v1.workspaces(params.workspace_sid).taskQueues(q.sid).statistics().fetch()
                );
                return { queue: q, stats };
              } catch {
                return { queue: q, stats: null };
              }
            })
          );

          // Build queue cards
          const queueCards = queueStats.map(({ queue, stats }) => {
            const tasksInQueue = stats?.realtime?.tasks_by_status?.pending || 0;
            const avgWaitTime = stats?.realtime?.tasks_by_status?.wait_duration_in_queue_until_accepted?.avg || 0;
            const availableWorkers = stats?.realtime?.activity_statistics?.find((a: any) => a.friendly_name === 'Available')?.workers || 0;

            const depth = Math.min(100, (tasksInQueue / 10) * 100);
            let depthColor: 'green' | 'yellow' | 'red' = 'green';
            if (tasksInQueue > 10) depthColor = 'red';
            else if (tasksInQueue > 5) depthColor = 'yellow';

            return `
              <div class="card">
                <div class="card-header" style="display: flex; justify-content: space-between; align-items: center;">
                  <strong>${queue.friendlyName}</strong>
                  ${renderer.badge(`${tasksInQueue} tasks`, tasksInQueue === 0 ? 'success' : tasksInQueue > 5 ? 'danger' : 'warning')}
                </div>
                <div style="margin-top: 12px;">
                  <div class="small muted">Queue Depth</div>
                  ${renderer.progressBar(depth, depthColor)}
                </div>
                <div class="card-grid card-grid-2" style="margin-top: 12px;">
                  <div>
                    <div class="small muted">Avg Wait Time</div>
                    <strong>${Math.round(avgWaitTime)}s</strong>
                  </div>
                  <div>
                    <div class="small muted">Available Agents</div>
                    <strong>${availableWorkers}</strong>
                  </div>
                </div>
                <div class="small dim" style="margin-top: 8px;">${queue.sid}</div>
              </div>
            `;
          }).join('');

          const html = renderer.appLayout(
            '📋 Queue Manager',
            `Workspace: ${params.workspace_sid}`,
            `
            <div class="card-grid card-grid-2">
              ${queueCards}
            </div>
            `
          );

          return this.appResult(html,
            `Queue Status:\n` +
            queueStats.map(({ queue, stats }) => {
              const tasksInQueue = stats?.realtime?.tasks_by_status?.pending || 0;
              const avgWaitTime = stats?.realtime?.tasks_by_status?.wait_duration_in_queue_until_accepted?.avg || 0;
              return `  ${queue.friendlyName}: ${tasksInQueue} tasks, ${Math.round(avgWaitTime)}s avg wait`;
            }).join('\n')
          );
        } catch (err: any) {
          return this.errorResult(`Failed to fetch queue statistics: ${err.message}`);
        }
      },
    });

    // ─── twilio_route_call ───
    this.registerTool({
      name: 'twilio_route_call',
      description: 'Create or update a task routing — assign to queue or specific worker, set priority.',
      category: 'contact-center',
      safety: 'yellow',
      tier: 2,
      annotations: { costHint: false },
      inputSchema: z.object({
        workspace_sid: z.string().describe('TaskRouter workspace SID'),
        task_sid: z.string().optional().describe('Existing task SID to update (creates new if omitted)'),
        attributes: z.string().optional().describe('Task attributes as JSON string'),
        queue_name: z.string().optional().describe('Queue name to route to'),
        worker_name: z.string().optional().describe('Worker name to assign to directly'),
        priority: z.number().min(0).max(100).optional().describe('Task priority (0-100, default 0)'),
      }),
      _meta: {
        labels: {
          category: "contact-center",
          access: "read",
          complexity: "simple"
        }
      },
      handler: async (params) => {
        try {
          const attributes = params.attributes ? JSON.parse(params.attributes) : { type: 'call' };
          
          // If creating a new task
          if (!params.task_sid) {
            // Find the first workflow in the workspace to use as default
            const workflows = await this.client.execute(c =>
              c.taskrouter.v1.workspaces(params.workspace_sid).workflows.list({ limit: 1 })
            );
            if (workflows.length === 0) {
              return this.errorResult('No workflows found in workspace. Create a workflow first.');
            }

            const task = await this.client.execute(c =>
              c.taskrouter.v1.workspaces(params.workspace_sid).tasks.create({
                attributes: JSON.stringify(attributes),
                workflowSid: workflows[0].sid,
                priority: params.priority || 0,
              })
            );

            return this.textResult(
              `Task created!\n` +
              `  SID: ${task.sid}\n` +
              `  Priority: ${task.priority}\n` +
              `  Status: ${task.assignmentStatus}`
            );
          }

          // Update existing task
          const task = await this.client.execute(c =>
            c.taskrouter.v1.workspaces(params.workspace_sid).tasks(params.task_sid!).update({
              attributes: JSON.stringify(attributes),
              priority: params.priority,
            })
          );

          return this.textResult(
            `Task updated!\n` +
            `  SID: ${task.sid}\n` +
            `  Priority: ${task.priority}\n` +
            `  Status: ${task.assignmentStatus}`
          );
        } catch (err: any) {
          return this.errorResult(`Failed to route task: ${err.message}`);
        }
      },
    });

    // ─── twilio_shift_schedule ───
    this.registerTool({
      name: 'twilio_shift_schedule',
      description: 'Batch update worker activities — clock in/out multiple agents at once.',
      category: 'contact-center',
      safety: 'yellow',
      tier: 2,
      annotations: { costHint: false },
      inputSchema: z.object({
        workspace_sid: z.string().describe('TaskRouter workspace SID'),
        updates: z.array(z.object({
          worker_name: z.string().describe('Worker/agent name'),
          activity: z.enum(['Available', 'Unavailable', 'Break', 'Offline']).describe('New activity'),
        })).describe('Worker activity updates'),
      }),
      _meta: {
        labels: {
          category: "contact-center",
          access: "read",
          complexity: "simple"
        }
      },
      handler: async (params) => {
        try {
          // Fetch workers and activities
          const [workers, activities] = await Promise.all([
            this.client.execute(c =>
              c.taskrouter.v1.workspaces(params.workspace_sid).workers.list({ limit: 100 })
            ),
            this.client.execute(c =>
              c.taskrouter.v1.workspaces(params.workspace_sid).activities.list()
            ),
          ]);

          const workerMap = new Map(workers.map(w => [w.friendlyName, w]));
          const activityMap = new Map(activities.map(a => [a.friendlyName, a.sid]));

          // Process updates
          const results = await Promise.all(
            params.updates.map(async (update: { worker_name: string; activity: string }) => {
              const worker = workerMap.get(update.worker_name);
              const activitySid = activityMap.get(update.activity);

              if (!worker) {
                return { name: update.worker_name, status: 'not found', error: true };
              }
              if (!activitySid) {
                return { name: update.worker_name, status: 'invalid activity', error: true };
              }

              try {
                await this.client.execute(c =>
                  c.taskrouter.v1.workspaces(params.workspace_sid).workers(worker.sid).update({
                    activitySid,
                  })
                );
                return { name: update.worker_name, status: update.activity, error: false };
              } catch (err: any) {
                return { name: update.worker_name, status: err.message, error: true };
              }
            })
          );

          const successful = results.filter(r => !r.error);
          const failed = results.filter(r => r.error);

          return this.textResult(
            `Shift schedule updated:\n` +
            `  Successful: ${successful.length}/${results.length}\n` +
            successful.map(r => `    ✓ ${r.name} → ${r.status}`).join('\n') +
            (failed.length > 0 ? '\n  Failed:\n' + failed.map(r => `    ✗ ${r.name}: ${r.status}`).join('\n') : '')
          );
        } catch (err: any) {
          return this.errorResult(`Failed to update shift schedule: ${err.message}`);
        }
      },
    });
  }
}
