import { DeesElement, customElement, html, css, cssManager, state, type TemplateResult } from '../plugins.js';
import { deesCatalog } from '../plugins.js';
import { appState, type IAppState } from '../state/appstate.js';
import { viewHostCss } from './shared/index.js';
import type { IStatsTile } from '@design.estate/dees-catalog';

const { DeesModal, DeesToast } = deesCatalog;

// ---------------------------------------------------------------------------
// IVR types (mirrors ts/config.ts)
// ---------------------------------------------------------------------------

type TIvrAction =
  | { type: 'route-extension'; extensionId: string }
  | { type: 'route-voicemail'; boxId: string }
  | { type: 'submenu'; menuId: string }
  | { type: 'play-message'; promptId: string }
  | { type: 'transfer'; number: string; providerId?: string }
  | { type: 'repeat' }
  | { type: 'hangup' };

interface IIvrMenuEntry {
  digit: string;
  action: TIvrAction;
}

interface IIvrMenu {
  id: string;
  name: string;
  promptText: string;
  promptVoice?: string;
  entries: IIvrMenuEntry[];
  timeoutSec?: number;
  maxRetries?: number;
  timeoutAction: TIvrAction;
  invalidAction: TIvrAction;
}

interface IIvrConfig {
  enabled: boolean;
  menus: IIvrMenu[];
  entryMenuId: string;
}

// ---------------------------------------------------------------------------
// Helpers
// ---------------------------------------------------------------------------

function slugify(name: string): string {
  return name
    .toLowerCase()
    .replace(/[^a-z0-9]+/g, '-')
    .replace(/^-|-$/g, '') || `menu-${Date.now()}`;
}

const VOICE_OPTIONS = [
  { option: 'af_bella (Female)', key: 'af_bella' },
  { option: 'af_sarah (Female)', key: 'af_sarah' },
  { option: 'am_adam (Male)', key: 'am_adam' },
  { option: 'bf_alice (Female)', key: 'bf_alice' },
];

const ACTION_TYPE_OPTIONS = [
  { option: 'Route to Extension', key: 'route-extension' },
  { option: 'Route to Voicemail', key: 'route-voicemail' },
  { option: 'Submenu', key: 'submenu' },
  { option: 'Play Message', key: 'play-message' },
  { option: 'Transfer', key: 'transfer' },
  { option: 'Repeat', key: 'repeat' },
  { option: 'Hangup', key: 'hangup' },
];

const DIGIT_OPTIONS = ['1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '*', '#'];

function describeAction(action: TIvrAction): string {
  switch (action.type) {
    case 'route-extension': return `Extension: ${action.extensionId}`;
    case 'route-voicemail': return `Voicemail: ${action.boxId}`;
    case 'submenu': return `Submenu: ${action.menuId}`;
    case 'play-message': return `Play: ${action.promptId}`;
    case 'transfer': return `Transfer: ${action.number}${action.providerId ? ` (${action.providerId})` : ''}`;
    case 'repeat': return 'Repeat';
    case 'hangup': return 'Hangup';
    default: return 'Unknown';
  }
}

function makeDefaultAction(): TIvrAction {
  return { type: 'hangup' };
}

// ---------------------------------------------------------------------------
// View element
// ---------------------------------------------------------------------------

@customElement('sipproxy-view-ivr')
export class SipproxyViewIvr extends DeesElement {
  @state() accessor appData: IAppState = appState.getState();
  @state() accessor config: any = null;

  public static styles = [
    cssManager.defaultStyles,
    viewHostCss,
    css`
      .view-section { margin-bottom: 24px; }
    `,
  ];

  // ---- lifecycle -----------------------------------------------------------

  connectedCallback() {
    super.connectedCallback();
    this.rxSubscriptions.push({
      unsubscribe: appState.subscribe((s) => { this.appData = s; }),
    } as any);
    this.loadConfig();
  }

  private async loadConfig() {
    try {
      this.config = await appState.apiGetConfig();
    } catch {
      // Will show empty state.
    }
  }

  private getIvrConfig(): IIvrConfig {
    return this.config?.ivr || { enabled: false, menus: [], entryMenuId: '' };
  }

  // ---- stats tiles ---------------------------------------------------------

  private getStatsTiles(): IStatsTile[] {
    const ivr = this.getIvrConfig();
    const entryMenu = ivr.menus.find((m) => m.id === ivr.entryMenuId);

    return [
      {
        id: 'total-menus',
        title: 'Total Menus',
        value: ivr.menus.length,
        type: 'number',
        icon: 'lucide:ListTree',
        description: 'IVR menu definitions',
      },
      {
        id: 'entry-menu',
        title: 'Entry Menu',
        value: entryMenu?.name || '(none)',
        type: 'text' as any,
        icon: 'lucide:DoorOpen',
        description: entryMenu ? `ID: ${entryMenu.id}` : 'No entry menu set',
      },
      {
        id: 'status',
        title: 'Status',
        value: ivr.enabled ? 'Enabled' : 'Disabled',
        type: 'text' as any,
        icon: ivr.enabled ? 'lucide:CheckCircle' : 'lucide:XCircle',
        color: ivr.enabled ? 'hsl(142.1 76.2% 36.3%)' : 'hsl(0 84.2% 60.2%)',
        description: ivr.enabled ? 'IVR is active' : 'IVR is inactive',
      },
    ];
  }

  // ---- table columns -------------------------------------------------------

  private getColumns() {
    const ivr = this.getIvrConfig();
    return [
      {
        key: 'name',
        header: 'Name',
        sortable: true,
        renderer: (val: string, row: IIvrMenu) => {
          const isEntry = row.id === ivr.entryMenuId;
          return html`
            <span>${val}</span>
            ${isEntry ? html`<span style="display:inline-block;margin-left:8px;padding:1px 6px;border-radius:4px;font-size:.65rem;font-weight:600;text-transform:uppercase;background:#1e3a5f;color:#60a5fa">entry</span>` : ''}
          `;
        },
      },
      {
        key: 'promptText',
        header: 'Prompt',
        renderer: (val: string) => {
          const truncated = val && val.length > 60 ? val.slice(0, 60) + '...' : val || '--';
          return html`<span style="font-size:.82rem;color:#94a3b8">${truncated}</span>`;
        },
      },
      {
        key: 'entries',
        header: 'Digits',
        renderer: (_val: any, row: IIvrMenu) => {
          const digits = (row.entries || []).map((e) => e.digit).join(', ');
          return html`<span style="font-family:'JetBrains Mono',monospace;font-size:.75rem">${digits || '(none)'}</span>`;
        },
      },
      {
        key: 'timeoutAction',
        header: 'Timeout Action',
        renderer: (_val: any, row: IIvrMenu) => {
          return html`<span style="font-size:.82rem;color:#94a3b8">${describeAction(row.timeoutAction)}</span>`;
        },
      },
    ];
  }

  // ---- table actions -------------------------------------------------------

  private getDataActions() {
    return [
      {
        name: 'Add Menu',
        iconName: 'lucide:plus' as any,
        type: ['header'] as any,
        actionFunc: async () => {
          await this.openMenuEditor(null);
        },
      },
      {
        name: 'Edit',
        iconName: 'lucide:pencil' as any,
        type: ['inRow'] as any,
        actionFunc: async ({ item }: { item: IIvrMenu }) => {
          await this.openMenuEditor(item);
        },
      },
      {
        name: 'Set as Entry',
        iconName: 'lucide:DoorOpen' as any,
        type: ['inRow'] as any,
        actionFunc: async ({ item }: { item: IIvrMenu }) => {
          await this.setEntryMenu(item.id);
        },
      },
      {
        name: 'Delete',
        iconName: 'lucide:Trash2' as any,
        type: ['inRow'] as any,
        actionFunc: async ({ item }: { item: IIvrMenu }) => {
          await this.confirmDeleteMenu(item);
        },
      },
    ];
  }

  // ---- toggle enabled ------------------------------------------------------

  private async toggleEnabled() {
    const ivr = this.getIvrConfig();
    const updated: IIvrConfig = { ...ivr, enabled: !ivr.enabled };
    const result = await appState.apiSaveConfig({ ivr: updated });
    if (result.ok) {
      DeesToast.success(updated.enabled ? 'IVR enabled' : 'IVR disabled');
      await this.loadConfig();
    } else {
      DeesToast.error('Failed to update IVR status');
    }
  }

  // ---- set entry menu ------------------------------------------------------

  private async setEntryMenu(menuId: string) {
    const ivr = this.getIvrConfig();
    const updated: IIvrConfig = { ...ivr, entryMenuId: menuId };
    const result = await appState.apiSaveConfig({ ivr: updated });
    if (result.ok) {
      DeesToast.success('Entry menu updated');
      await this.loadConfig();
    } else {
      DeesToast.error('Failed to set entry menu');
    }
  }

  // ---- delete menu ---------------------------------------------------------

  private async confirmDeleteMenu(menu: IIvrMenu) {
    await DeesModal.createAndShow({
      heading: 'Delete IVR Menu',
      width: 'small',
      showCloseButton: true,
      content: html`
        <div style="padding:8px 0;font-size:.9rem;color:#e2e8f0;">
          Are you sure you want to delete
          <strong style="color:#f87171;">${menu.name}</strong>?
          This action cannot be undone.
        </div>
      `,
      menuOptions: [
        {
          name: 'Cancel',
          iconName: 'lucide:x',
          action: async (modalRef: any) => { modalRef.destroy(); },
        },
        {
          name: 'Delete',
          iconName: 'lucide:Trash2',
          action: async (modalRef: any) => {
            const ivr = this.getIvrConfig();
            const menus = ivr.menus.filter((m) => m.id !== menu.id);
            const updated: IIvrConfig = {
              ...ivr,
              menus,
              entryMenuId: ivr.entryMenuId === menu.id ? '' : ivr.entryMenuId,
            };
            const result = await appState.apiSaveConfig({ ivr: updated });
            if (result.ok) {
              modalRef.destroy();
              DeesToast.success(`Menu "${menu.name}" deleted`);
              await this.loadConfig();
            } else {
              DeesToast.error('Failed to delete menu');
            }
          },
        },
      ],
    });
  }

  // ---- action editor helper ------------------------------------------------

  private renderActionEditor(
    action: TIvrAction,
    onChange: (a: TIvrAction) => void,
    label: string,
    cfg: any,
  ): TemplateResult {
    const devices = cfg?.devices || [];
    const menus: IIvrMenu[] = cfg?.ivr?.menus || [];
    const providers = cfg?.providers || [];

    const currentType = ACTION_TYPE_OPTIONS.find((o) => o.key === action.type) || ACTION_TYPE_OPTIONS[ACTION_TYPE_OPTIONS.length - 1];

    return html`
      <div style="margin-bottom:12px;">
        <div style="font-size:.75rem;color:#94a3b8;text-transform:uppercase;letter-spacing:.04em;margin-bottom:6px;font-weight:600;">${label}</div>
        <dees-input-dropdown
          .label=${'Action Type'}
          .selectedOption=${currentType}
          .options=${ACTION_TYPE_OPTIONS}
          @selectedOption=${(e: CustomEvent) => {
            const type = e.detail.key;
            switch (type) {
              case 'route-extension': onChange({ type, extensionId: devices[0]?.extension || '100' }); break;
              case 'route-voicemail': onChange({ type, boxId: '' }); break;
              case 'submenu': onChange({ type, menuId: menus[0]?.id || '' }); break;
              case 'play-message': onChange({ type, promptId: '' }); break;
              case 'transfer': onChange({ type, number: '' }); break;
              case 'repeat': onChange({ type }); break;
              case 'hangup': onChange({ type }); break;
            }
          }}
        ></dees-input-dropdown>

        ${action.type === 'route-extension' ? html`
          <dees-input-dropdown
            .label=${'Extension'}
            .selectedOption=${{ option: action.extensionId, key: action.extensionId }}
            .options=${devices.map((d: any) => ({ option: `${d.displayName} (${d.extension})`, key: d.extension }))}
            @selectedOption=${(e: CustomEvent) => { onChange({ ...action, extensionId: e.detail.key }); }}
          ></dees-input-dropdown>
        ` : ''}

        ${action.type === 'route-voicemail' ? html`
          <dees-input-text
            .label=${'Voicemail Box ID'}
            .value=${action.boxId}
            @input=${(e: Event) => { onChange({ ...action, boxId: (e.target as any).value }); }}
          ></dees-input-text>
        ` : ''}

        ${action.type === 'submenu' ? html`
          <dees-input-dropdown
            .label=${'Menu'}
            .selectedOption=${menus.find((m) => m.id === action.menuId)
              ? { option: menus.find((m) => m.id === action.menuId)!.name, key: action.menuId }
              : { option: '(select)', key: '' }}
            .options=${menus.map((m) => ({ option: m.name, key: m.id }))}
            @selectedOption=${(e: CustomEvent) => { onChange({ ...action, menuId: e.detail.key }); }}
          ></dees-input-dropdown>
        ` : ''}

        ${action.type === 'play-message' ? html`
          <dees-input-text
            .label=${'Prompt ID'}
            .value=${action.promptId}
            @input=${(e: Event) => { onChange({ ...action, promptId: (e.target as any).value }); }}
          ></dees-input-text>
        ` : ''}

        ${action.type === 'transfer' ? html`
          <dees-input-text
            .label=${'Transfer Number'}
            .value=${action.number}
            @input=${(e: Event) => { onChange({ ...action, number: (e.target as any).value }); }}
          ></dees-input-text>
          <dees-input-dropdown
            .label=${'Provider (optional)'}
            .selectedOption=${action.providerId
              ? { option: action.providerId, key: action.providerId }
              : { option: '(default)', key: '' }}
            .options=${[
              { option: '(default)', key: '' },
              ...providers.map((p: any) => ({ option: p.displayName || p.id, key: p.id })),
            ]}
            @selectedOption=${(e: CustomEvent) => { onChange({ ...action, providerId: e.detail.key || undefined }); }}
          ></dees-input-dropdown>
        ` : ''}
      </div>
    `;
  }

  // ---- menu editor modal ---------------------------------------------------

  private async openMenuEditor(existing: IIvrMenu | null) {
    const cfg = this.config;

    const formData: IIvrMenu = existing
      ? JSON.parse(JSON.stringify(existing))
      : {
          id: '',
          name: '',
          promptText: '',
          promptVoice: 'af_bella',
          entries: [],
          timeoutSec: 5,
          maxRetries: 3,
          timeoutAction: { type: 'hangup' as const },
          invalidAction: { type: 'repeat' as const },
        };

    // For re-rendering the modal content on state changes we track a version counter.
    let version = 0;
    const modalContentId = `ivr-modal-${Date.now()}`;

    const rerenderContent = () => {
      version++;
      const container = document.querySelector(`#${modalContentId}`) as HTMLElement
        || document.getElementById(modalContentId);
      if (container) {
        // Force a re-render by removing and re-adding the modal content.
        // We can't use lit's render directly here, so we close and reopen.
      }
    };

    const buildContent = (): TemplateResult => html`
      <div style="display:flex;flex-direction:column;gap:12px;padding:4px 0;">
        <dees-input-text
          .key=${'name'} .label=${'Menu Name'} .value=${formData.name}
          @input=${(e: Event) => {
            formData.name = (e.target as any).value;
            if (!existing) {
              formData.id = slugify(formData.name);
            }
          }}
        ></dees-input-text>

        <dees-input-text
          .key=${'id'} .label=${'Menu ID'} .value=${formData.id}
          .description=${'Auto-generated from name. Editable for custom IDs.'}
          @input=${(e: Event) => { formData.id = (e.target as any).value; }}
        ></dees-input-text>

        <dees-input-text
          .key=${'promptText'} .label=${'Prompt Text (TTS)'}
          .value=${formData.promptText}
          .description=${'Text that will be read aloud to the caller.'}
          @input=${(e: Event) => { formData.promptText = (e.target as any).value; }}
        ></dees-input-text>

        <dees-input-dropdown
          .key=${'promptVoice'} .label=${'Voice'}
          .selectedOption=${VOICE_OPTIONS.find((v) => v.key === formData.promptVoice) || VOICE_OPTIONS[0]}
          .options=${VOICE_OPTIONS}
          @selectedOption=${(e: CustomEvent) => { formData.promptVoice = e.detail.key; }}
        ></dees-input-dropdown>

        <div style="margin-top:8px;padding-top:12px;border-top:1px solid #334155;">
          <div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:8px;">
            <div style="font-size:.75rem;color:#94a3b8;text-transform:uppercase;letter-spacing:.04em;font-weight:600;">
              Digit Entries
            </div>
            <div
              style="font-size:.75rem;color:#60a5fa;cursor:pointer;user-select:none;"
              @click=${() => {
                const usedDigits = new Set(formData.entries.map((e) => e.digit));
                const nextDigit = DIGIT_OPTIONS.find((d) => !usedDigits.has(d)) || '1';
                formData.entries = [...formData.entries, { digit: nextDigit, action: makeDefaultAction() }];
                rerenderContent();
              }}
            >+ Add Digit</div>
          </div>

          ${formData.entries.length === 0
            ? html`<div style="font-size:.82rem;color:#64748b;font-style:italic;margin-bottom:8px;">No digit entries configured.</div>`
            : formData.entries.map((entry, idx) => html`
              <div style="padding:8px;margin-bottom:8px;border:1px solid #334155;border-radius:6px;background:#0f172a;">
                <div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:8px;">
                  <dees-input-dropdown
                    .label=${'Digit'}
                    .selectedOption=${{ option: entry.digit, key: entry.digit }}
                    .options=${DIGIT_OPTIONS.map((d) => ({ option: d, key: d }))}
                    @selectedOption=${(e: CustomEvent) => {
                      formData.entries[idx].digit = e.detail.key;
                    }}
                  ></dees-input-dropdown>
                  <div
                    style="font-size:.75rem;color:#f87171;cursor:pointer;user-select:none;margin-left:12px;padding:4px 8px;"
                    @click=${() => {
                      formData.entries = formData.entries.filter((_, i) => i !== idx);
                      rerenderContent();
                    }}
                  >Remove</div>
                </div>
                ${this.renderActionEditor(
                  entry.action,
                  (a) => { formData.entries[idx].action = a; rerenderContent(); },
                  'Action',
                  cfg,
                )}
              </div>
            `)
          }
        </div>

        <div style="margin-top:8px;padding-top:12px;border-top:1px solid #334155;">
          <div style="font-size:.75rem;color:#94a3b8;text-transform:uppercase;letter-spacing:.04em;margin-bottom:8px;font-weight:600;">
            Timeout Settings
          </div>
          <div style="display:flex;gap:12px;">
            <dees-input-text
              .key=${'timeoutSec'} .label=${'Timeout (sec)'}
              .value=${String(formData.timeoutSec ?? 5)}
              @input=${(e: Event) => { formData.timeoutSec = parseInt((e.target as any).value, 10) || 5; }}
            ></dees-input-text>
            <dees-input-text
              .key=${'maxRetries'} .label=${'Max Retries'}
              .value=${String(formData.maxRetries ?? 3)}
              @input=${(e: Event) => { formData.maxRetries = parseInt((e.target as any).value, 10) || 3; }}
            ></dees-input-text>
          </div>
        </div>

        <div style="margin-top:8px;padding-top:12px;border-top:1px solid #334155;">
          ${this.renderActionEditor(
            formData.timeoutAction,
            (a) => { formData.timeoutAction = a; rerenderContent(); },
            'Timeout Action (no digit pressed)',
            cfg,
          )}
          ${this.renderActionEditor(
            formData.invalidAction,
            (a) => { formData.invalidAction = a; rerenderContent(); },
            'Invalid Digit Action',
            cfg,
          )}
        </div>
      </div>
    `;

    await DeesModal.createAndShow({
      heading: existing ? `Edit Menu: ${existing.name}` : 'New IVR Menu',
      width: 'small',
      showCloseButton: true,
      content: html`<div id="${modalContentId}">${buildContent()}</div>`,
      menuOptions: [
        {
          name: 'Cancel',
          iconName: 'lucide:x',
          action: async (modalRef: any) => { modalRef.destroy(); },
        },
        {
          name: 'Save',
          iconName: 'lucide:check',
          action: async (modalRef: any) => {
            if (!formData.name.trim()) {
              DeesToast.error('Menu name is required');
              return;
            }
            if (!formData.id.trim()) {
              DeesToast.error('Menu ID is required');
              return;
            }
            if (!formData.promptText.trim()) {
              DeesToast.error('Prompt text is required');
              return;
            }

            const ivr = this.getIvrConfig();
            const menus = [...ivr.menus];
            const idx = menus.findIndex((m) => m.id === (existing?.id || formData.id));
            if (idx >= 0) {
              menus[idx] = formData;
            } else {
              menus.push(formData);
            }

            const updated: IIvrConfig = {
              ...ivr,
              menus,
              // Auto-set entry menu if this is the first menu.
              entryMenuId: ivr.entryMenuId || formData.id,
            };

            const result = await appState.apiSaveConfig({ ivr: updated });
            if (result.ok) {
              modalRef.destroy();
              DeesToast.success(existing ? 'Menu updated' : 'Menu created');
              await this.loadConfig();
            } else {
              DeesToast.error('Failed to save menu');
            }
          },
        },
      ],
    });
  }

  // ---- render --------------------------------------------------------------

  public render(): TemplateResult {
    const ivr = this.getIvrConfig();
    const menus = ivr.menus || [];

    return html`
      <dees-heading level="3">IVR</dees-heading>

      <div class="view-section">
        <dees-statsgrid
          .tiles=${this.getStatsTiles()}
          .minTileWidth=${220}
          .gap=${16}
        ></dees-statsgrid>
      </div>

      <div class="view-section" style="display:flex;align-items:center;gap:12px;margin-bottom:16px;">
        <dees-input-checkbox
          .key=${'ivr-enabled'}
          .label=${'Enable IVR System'}
          .value=${ivr.enabled}
          @newValue=${() => { this.toggleEnabled(); }}
        ></dees-input-checkbox>
      </div>

      <div class="view-section">
        <dees-table
          heading1="IVR Menus"
          heading2="${menus.length} configured"
          dataName="menus"
          .data=${menus}
          .rowKey=${'id'}
          .columns=${this.getColumns()}
          .dataActions=${this.getDataActions()}
        ></dees-table>
      </div>
    `;
  }
}
