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';

// ---------------------------------------------------------------------------
// Voicemail message shape (mirrors server IVoicemailMessage)
// ---------------------------------------------------------------------------
interface IVoicemailMessage {
  id: string;
  boxId: string;
  callerNumber: string;
  callerName?: string;
  timestamp: number;
  durationMs: number;
  fileName: string;
  heard: boolean;
}

interface IVoiceboxRow {
  id: string;
  unheardCount: number;
  selected: boolean;
}

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

function formatDuration(ms: number): string {
  const totalSec = Math.round(ms / 1000);
  const min = Math.floor(totalSec / 60);
  const sec = totalSec % 60;
  return `${min}:${sec.toString().padStart(2, '0')}`;
}

function formatDateTime(ts: number): string {
  const d = new Date(ts);
  const date = d.toLocaleDateString(undefined, { year: 'numeric', month: 'short', day: 'numeric' });
  const time = d.toLocaleTimeString(undefined, { hour: '2-digit', minute: '2-digit' });
  return `${date} ${time}`;
}

// ---------------------------------------------------------------------------
// View element
// ---------------------------------------------------------------------------
@customElement('sipproxy-view-voicemail')
export class SipproxyViewVoicemail extends DeesElement {
  @state() accessor appData: IAppState = appState.getState();
  @state() accessor messages: IVoicemailMessage[] = [];
  @state() accessor voiceboxIds: string[] = [];
  @state() accessor selectedBoxId: string = '';
  @state() accessor playingMessageId: string | null = null;
  @state() accessor loading: boolean = false;

  private audioElement: HTMLAudioElement | null = null;

  public static styles = [
    cssManager.defaultStyles,
    viewHostCss,
    css`
      :host {
        display: block;
        padding: 16px;
      }
      .view-section {
        margin-bottom: 24px;
      }
      .audio-player {
        display: flex;
        align-items: center;
        gap: 8px;
        padding: 8px 12px;
        background: #1e293b;
        border-radius: 8px;
        margin-top: 16px;
      }
      .audio-player audio {
        flex: 1;
        height: 32px;
      }
      .audio-player .close-btn {
        cursor: pointer;
        color: #94a3b8;
        font-size: 1.1rem;
        padding: 2px 6px;
        border-radius: 4px;
        transition: background 0.15s;
      }
      .audio-player .close-btn:hover {
        background: #334155;
        color: #e2e8f0;
      }
      .empty-state {
        text-align: center;
        padding: 48px 16px;
        color: #64748b;
        font-size: 0.9rem;
      }
      .empty-state .icon {
        font-size: 2.5rem;
        margin-bottom: 12px;
        opacity: 0.5;
      }
    `,
  ];

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

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

  disconnectedCallback() {
    super.disconnectedCallback();
    this.stopAudio();
  }

  // ---- data loading --------------------------------------------------------

  private async loadVoiceboxes() {
    try {
      const cfg = await appState.apiGetConfig();
      const boxes: { id: string }[] = cfg.voiceboxes || [];
      this.voiceboxIds = boxes.map((b) => b.id);
      const nextSelectedBoxId = this.voiceboxIds.includes(this.selectedBoxId)
        ? this.selectedBoxId
        : (this.voiceboxIds[0] || '');
      this.selectedBoxId = nextSelectedBoxId;
      await this.loadMessages();
    } catch {
      // Config unavailable.
    }
  }

  private async loadMessages() {
    if (!this.selectedBoxId) {
      this.messages = [];
      return;
    }
    this.loading = true;
    try {
      const res = await fetch(`/api/voicemail/${encodeURIComponent(this.selectedBoxId)}`);
      const data = await res.json();
      this.messages = data.messages || [];
    } catch {
      this.messages = [];
    }
    this.loading = false;
  }

  private async selectBox(boxId: string) {
    if (boxId === this.selectedBoxId) {
      return;
    }
    this.selectedBoxId = boxId;
    this.stopAudio();
    await this.loadMessages();
  }

  private getVoiceboxRows(): IVoiceboxRow[] {
    return this.voiceboxIds.map((id) => ({
      id,
      unheardCount: this.appData.voicemailCounts[id] || 0,
      selected: id === this.selectedBoxId,
    }));
  }

  // ---- audio playback ------------------------------------------------------

  private playMessage(msg: IVoicemailMessage) {
    this.stopAudio();
    const url = `/api/voicemail/${encodeURIComponent(msg.boxId)}/${encodeURIComponent(msg.id)}/audio`;
    const audio = new Audio(url);
    this.audioElement = audio;
    this.playingMessageId = msg.id;

    audio.addEventListener('ended', () => {
      this.playingMessageId = null;
      // Auto-mark as heard after playback completes.
      if (!msg.heard) {
        this.markHeard(msg);
      }
    });

    audio.addEventListener('error', () => {
      this.playingMessageId = null;
      deesCatalog.DeesToast.error('Failed to play audio');
    });

    audio.play().catch(() => {
      this.playingMessageId = null;
    });
  }

  private stopAudio() {
    if (this.audioElement) {
      this.audioElement.pause();
      this.audioElement.src = '';
      this.audioElement = null;
    }
    this.playingMessageId = null;
  }

  // ---- message actions -----------------------------------------------------

  private async markHeard(msg: IVoicemailMessage) {
    try {
      await fetch(`/api/voicemail/${encodeURIComponent(msg.boxId)}/${encodeURIComponent(msg.id)}/heard`, {
        method: 'POST',
      });
      // Update local state without full reload.
      this.messages = this.messages.map((m) =>
        m.id === msg.id ? { ...m, heard: true } : m,
      );
    } catch {
      deesCatalog.DeesToast.error('Failed to mark message as heard');
    }
  }

  private async deleteMessage(msg: IVoicemailMessage) {
    const { DeesModal } = await import('@design.estate/dees-catalog');
    await DeesModal.createAndShow({
      heading: 'Delete Voicemail',
      width: 'small',
      showCloseButton: true,
      content: html`
        <div style="padding:8px 0;font-size:.9rem;color:#e2e8f0;">
          Are you sure you want to delete the voicemail from
          <strong style="color:#f87171;">${msg.callerName || msg.callerNumber}</strong>
          (${formatDateTime(msg.timestamp)})?
        </div>
      `,
      menuOptions: [
        {
          name: 'Cancel',
          iconName: 'lucide:x',
          action: async (modalRef: any) => { modalRef.destroy(); },
        },
        {
          name: 'Delete',
          iconName: 'lucide:Trash2',
          action: async (modalRef: any) => {
            try {
              await fetch(
                `/api/voicemail/${encodeURIComponent(msg.boxId)}/${encodeURIComponent(msg.id)}`,
                { method: 'DELETE' },
              );
              if (this.playingMessageId === msg.id) {
                this.stopAudio();
              }
              this.messages = this.messages.filter((m) => m.id !== msg.id);
              modalRef.destroy();
              deesCatalog.DeesToast.success('Voicemail deleted');
            } catch {
              deesCatalog.DeesToast.error('Failed to delete voicemail');
            }
          },
        },
      ],
    });
  }

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

  private getStatsTiles(): IStatsTile[] {
    const total = this.messages.length;
    const unheard = this.messages.filter((m) => !m.heard).length;

    return [
      {
        id: 'total',
        title: 'Total Messages',
        value: total,
        type: 'number',
        icon: 'lucide:voicemail',
        description: this.selectedBoxId ? `Box: ${this.selectedBoxId}` : 'No box selected',
      },
      {
        id: 'unheard',
        title: 'Unheard Messages',
        value: unheard,
        type: 'number',
        icon: 'lucide:BellRing',
        color: unheard > 0 ? 'hsl(0 84.2% 60.2%)' : 'hsl(142.1 76.2% 36.3%)',
        description: unheard > 0 ? 'Needs attention' : 'All caught up',
      },
    ];
  }

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

  private getColumns() {
    return [
      {
        key: 'callerNumber',
        header: 'Caller',
        sortable: true,
        renderer: (_val: string, row: IVoicemailMessage) => {
          const display = row.callerName
            ? html`<span>${row.callerName}</span><br><span style="font-size:.75rem;color:#64748b">${row.callerNumber}</span>`
            : html`<span style="font-family:'JetBrains Mono',monospace;font-size:.85rem">${row.callerNumber}</span>`;
          return html`<div>${display}</div>`;
        },
      },
      {
        key: 'timestamp',
        header: 'Date/Time',
        sortable: true,
        value: (row: IVoicemailMessage) => formatDateTime(row.timestamp),
        renderer: (val: string) =>
          html`<span style="font-size:.85rem">${val}</span>`,
      },
      {
        key: 'durationMs',
        header: 'Duration',
        sortable: true,
        value: (row: IVoicemailMessage) => formatDuration(row.durationMs),
        renderer: (val: string) =>
          html`<span style="font-family:'JetBrains Mono',monospace;font-size:.85rem">${val}</span>`,
      },
      {
        key: 'heard',
        header: 'Status',
        renderer: (val: boolean, row: IVoicemailMessage) => {
          const isPlaying = this.playingMessageId === row.id;
          if (isPlaying) {
            return html`
              <span style="display:inline-block;padding:2px 8px;border-radius:4px;font-size:.7rem;font-weight:600;text-transform:uppercase;background:#1e3a5f;color:#60a5fa">Playing</span>
            `;
          }
          const heard = val;
          const color = heard ? '#71717a' : '#f59e0b';
          const bg = heard ? '#3f3f46' : '#422006';
          const label = heard ? 'Heard' : 'New';
          return html`
            <span style="display:inline-block;padding:2px 8px;border-radius:4px;font-size:.7rem;font-weight:600;text-transform:uppercase;background:${bg};color:${color}">${label}</span>
          `;
        },
      },
    ];
  }

  private getVoiceboxColumns() {
    return [
      {
        key: 'id',
        header: 'Voicebox',
        sortable: true,
        renderer: (val: string, row: IVoiceboxRow) => html`
          <div style="display:flex;align-items:center;gap:10px;">
            <span style="font-family:'JetBrains Mono',monospace;font-size:.85rem;">${val}</span>
            ${row.selected ? html`
              <span style="display:inline-block;padding:2px 8px;border-radius:4px;font-size:.7rem;font-weight:600;text-transform:uppercase;background:#1e3a5f;color:#60a5fa">Viewing</span>
            ` : ''}
          </div>
        `,
      },
      {
        key: 'unheardCount',
        header: 'Unheard',
        sortable: true,
        renderer: (val: number) => {
          const hasUnheard = val > 0;
          return html`
            <span style="display:inline-block;padding:2px 8px;border-radius:4px;font-size:.75rem;font-weight:600;background:${hasUnheard ? '#422006' : '#1f2937'};color:${hasUnheard ? '#f59e0b' : '#94a3b8'}">${val}</span>
          `;
        },
      },
      {
        key: 'selected',
        header: 'Status',
        value: (row: IVoiceboxRow) => (row.selected ? 'Open' : 'Available'),
        renderer: (val: string, row: IVoiceboxRow) => html`
          <span style="color:${row.selected ? '#60a5fa' : '#94a3b8'};font-size:.8rem;">${val}</span>
        `,
      },
    ];
  }

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

  private getDataActions() {
    return [
      {
        name: 'Play',
        iconName: 'lucide:play',
        type: ['inRow'] as any,
        actionFunc: async (actionData: any) => {
          const msg = actionData.item as IVoicemailMessage;
          if (this.playingMessageId === msg.id) {
            this.stopAudio();
          } else {
            this.playMessage(msg);
          }
        },
      },
      {
        name: 'Mark Heard',
        iconName: 'lucide:check',
        type: ['inRow'] as any,
        actionFunc: async (actionData: any) => {
          const msg = actionData.item as IVoicemailMessage;
          if (!msg.heard) {
            await this.markHeard(msg);
            deesCatalog.DeesToast.success('Marked as heard');
          }
        },
      },
      {
        name: 'Delete',
        iconName: 'lucide:Trash2',
        type: ['inRow'] as any,
        actionFunc: async (actionData: any) => {
          await this.deleteMessage(actionData.item as IVoicemailMessage);
        },
      },
      {
        name: 'Refresh',
        iconName: 'lucide:refreshCw',
        type: ['header'] as any,
        actionFunc: async () => {
          await this.loadMessages();
          deesCatalog.DeesToast.success('Messages refreshed');
        },
      },
    ];
  }

  private getVoiceboxActions() {
    return [
      {
        name: 'View Messages',
        iconName: 'lucide:folder-open',
        type: ['inRow'] as any,
        actionFunc: async ({ item }: { item: IVoiceboxRow }) => {
          await this.selectBox(item.id);
        },
      },
      {
        name: 'Refresh Boxes',
        iconName: 'lucide:refreshCw',
        type: ['header'] as any,
        actionFunc: async () => {
          await this.loadVoiceboxes();
          deesCatalog.DeesToast.success('Voiceboxes refreshed');
        },
      },
    ];
  }

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

  public render(): TemplateResult {
    return html`
      <dees-heading level="3">Voicemail</dees-heading>

      <div class="view-section">
        <dees-table
          heading1="Voiceboxes"
          heading2="${this.voiceboxIds.length} configured"
          dataName="voiceboxes"
          .data=${this.getVoiceboxRows()}
          .rowKey=${'id'}
          .columns=${this.getVoiceboxColumns()}
          .dataActions=${this.getVoiceboxActions()}
        ></dees-table>
      </div>

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

      ${this.messages.length === 0 && !this.loading ? html`
        <div class="empty-state">
          <div class="icon">&#9993;</div>
          <div>No voicemail messages${this.selectedBoxId ? ` in box "${this.selectedBoxId}"` : ''}</div>
        </div>
      ` : html`
        <div class="view-section">
          <dees-table
            heading1="Voicemail"
            heading2="${this.messages.length} message${this.messages.length !== 1 ? 's' : ''}"
            dataName="voicemail"
            .data=${this.messages}
            .rowKey=${'id'}
            .searchable=${true}
            .columns=${this.getColumns()}
            .dataActions=${this.getDataActions()}
          ></dees-table>
        </div>
      `}

      ${this.playingMessageId ? html`
        <div class="audio-player">
          <span style="color:#60a5fa;font-size:.8rem;font-weight:600;">Now playing</span>
          <span style="flex:1"></span>
          <span class="close-btn" @click=${() => this.stopAudio()}>&#10005;</span>
        </div>
      ` : ''}
    `;
  }
}
