'use client';

/**
 * Call Candidate + Call Summary — the single-candidate AI call controls shown in
 * the Candidate Details header.
 *
 * Everything here reuses the EXISTING AI calling integration; no new provider,
 * no new call pipeline:
 *   • start   → POST /ai-calls/start/            (same endpoint the AI Screening tab uses)
 *   • state   → GET  /ai-calls/candidate/<id>/   (candidate-scoped read)
 *   • summary → GET  /ai-calls/<call_id>/transcript/  (already returns summary,
 *                                                     transcript + evaluation)
 *
 * The active provider is chosen server-side by settings.AI_CALL_PROVIDER, so this
 * UI is provider-agnostic — it does not care which calling backend is configured.
 */

import { useCallback, useEffect, useRef, useState } from 'react';
import { toast } from 'react-toastify';
import { api } from '@/lib/api';
import { useAuth } from '@/components/auth-context';
import { showConfirm } from '@/lib/confirm';

const POLL_MS = 4000;
const RUNNING = ['QUEUED', 'DIALING', 'IN_PROGRESS'];

/** Same status vocabulary and wording as the AI Screening table, so a call reads
 *  identically in both places. These are the statuses the AICall model defines. */
const STATUS_BADGES: Record<string, { cls: string; icon: string; label: string; pulse?: boolean }> = {
  QUEUED: { cls: 'bg-slate-100 text-slate-600 dark:bg-slate-800 dark:text-slate-300', icon: 'fa-clock', label: 'Queued', pulse: true },
  DIALING: { cls: 'bg-cyan-50 text-cyan-700 dark:bg-cyan-950/40 dark:text-cyan-300', icon: 'fa-phone-volume', label: 'Dialing', pulse: true },
  IN_PROGRESS: { cls: 'bg-indigo-50 text-indigo-700 dark:bg-indigo-950/40 dark:text-indigo-300', icon: 'fa-microphone-lines', label: 'Connected', pulse: true },
  COMPLETED: { cls: 'bg-emerald-50 text-emerald-700 dark:bg-emerald-950/40 dark:text-emerald-300', icon: 'fa-circle-check', label: 'Completed' },
  NO_ANSWER: { cls: 'bg-amber-50 text-amber-700 dark:bg-amber-950/40 dark:text-amber-300', icon: 'fa-phone-slash', label: 'No Answer' },
  BUSY: { cls: 'bg-orange-50 text-orange-700 dark:bg-orange-950/40 dark:text-orange-300', icon: 'fa-phone-slash', label: 'Busy' },
  CANCELLED: { cls: 'bg-slate-100 text-slate-600 dark:bg-slate-800 dark:text-slate-300', icon: 'fa-ban', label: 'Cancelled' },
  FAILED: { cls: 'bg-rose-50 text-rose-700 dark:bg-rose-950/40 dark:text-rose-300', icon: 'fa-triangle-exclamation', label: 'Failed' },
};

/** Outcomes where the call never connected and completed — no summary exists. */
const UNSUCCESSFUL = ['NO_ANSWER', 'BUSY', 'CANCELLED', 'FAILED'];

const REC_LABELS: Record<string, { label: string; cls: string }> = {
  QUALIFIED: { label: 'Qualified', cls: 'bg-emerald-50 text-emerald-700 dark:bg-emerald-950/40 dark:text-emerald-300' },
  REVIEW: { label: 'Needs Review', cls: 'bg-amber-50 text-amber-700 dark:bg-amber-950/40 dark:text-amber-300' },
  NOT_QUALIFIED: { label: 'Not Qualified', cls: 'bg-rose-50 text-rose-700 dark:bg-rose-950/40 dark:text-rose-300' },
};

interface CallBrief {
  call_id: number;
  status: string;
  duration: number | null;
  started_at: string;
  ended_at: string;
  summary: string;
  score: number | null;
  recommendation: string;
  error_message: string;
  has_transcript: boolean;
  job_id: number | null;
  job_title: string;
  /** Server-side truth: the call connected AND finished. Only then does a
   *  summary/transcript/score exist — the API withholds them otherwise. */
  is_completed: boolean;
}

interface CandidateCallState {
  has_phone: boolean;
  phone: string;
  jobs: { id: number; title: string; status: string }[];
  running_call_id: number | null;
  latest_call: CallBrief | null;
}

interface SummaryData extends CallBrief {
  candidate: string;
  job_title: string;
  transcript: string;
  utterances: { sequence: number; speaker: string; message: string }[];
  evaluation: {
    overall_score: number | null;
    classification: string;
    recommendation: string;
    strengths: string[];
    weaknesses: string[];
    summary: string;
  } | null;
}

/** Mirrors the backend's CanRunScreening permission (admin / recruiter / any
 *  *MANAGER*) and the AI Screening page's own gate. Not a new permission —
 *  the API enforces the same rule regardless of what this returns. */
function canCall(role?: string): boolean {
  const r = (role ?? '').toUpperCase();
  return r === 'ADMIN' || r === 'RECRUITER' || r.includes('MANAGER');
}

function fmtDuration(seconds: number | null): string {
  if (!seconds && seconds !== 0) return '—';
  const m = Math.floor(seconds / 60);
  const s = seconds % 60;
  return m > 0 ? `${m}m ${s}s` : `${s}s`;
}

export default function CandidateAICall({ candidateId }: { candidateId: number | string }) {
  const { user } = useAuth();
  const allowed = canCall(user?.role);

  const [state, setState] = useState<CandidateCallState | null>(null);
  const [starting, setStarting] = useState(false);
  const [summaryOpen, setSummaryOpen] = useState(false);
  const [summary, setSummary] = useState<SummaryData | null>(null);
  const [summaryLoading, setSummaryLoading] = useState(false);
  const pollRef = useRef<ReturnType<typeof setInterval> | null>(null);
  // Call ids already reported as failed, so the toast fires once per call rather
  // than on every poll tick. Seeded on the first load so a call that failed in an
  // earlier session doesn't pop an error just from opening the profile.
  const reportedRef = useRef<Set<number>>(new Set());
  const completedReportedRef = useRef<Set<number>>(new Set());
  const seededRef = useRef(false);

  const load = useCallback(async () => {
    try {
      const res = (await api.get(`/ai-calls/candidate/${candidateId}/`)) as { data?: CandidateCallState };
      const next = res?.data ?? null;
      setState(next);

      const call = next?.latest_call;
      const terminal = call && UNSUCCESSFUL.includes(call.status);
      if (!seededRef.current) {
        seededRef.current = true;
        if (terminal) reportedRef.current.add(call!.call_id);   // pre-existing, stay quiet
        if (call && call.status === 'COMPLETED') completedReportedRef.current.add(call.call_id);
        return;
      }
      // Surface error if call failed or was unsuccessful
      if (terminal && !reportedRef.current.has(call!.call_id)) {
        reportedRef.current.add(call!.call_id);
        const label = STATUS_BADGES[call!.status]?.label ?? call!.status;
        toast.error(call!.error_message
          ? `Call ${label.toLowerCase()}: ${call!.error_message}`
          : `Call ${label.toLowerCase()}.`);
      }
      // On call completion: show success toast and open summary modal automatically
      if (call && call.status === 'COMPLETED' && !completedReportedRef.current.has(call.call_id)) {
        completedReportedRef.current.add(call.call_id);
        toast.success('AI Screening call completed successfully!');
        const callId = call.call_id;
        setSummaryOpen(true);
        setSummaryLoading(true);
        api.get(`/ai-calls/${callId}/transcript/`).then((r: any) => {
          setSummary(r?.data ?? null);
        }).catch((e: any) => {
          setSummary(null);
          toast.error(e instanceof Error ? e.message : 'Could not load the call summary.');
        }).finally(() => {
          setSummaryLoading(false);
        });
      }
    } catch {
      setState(null);   // non-critical: the header simply shows no call controls
    }
  }, [candidateId]);

  useEffect(() => {
    if (allowed) load();
  }, [allowed, load]);

  // Poll only while a call is actually running, then stop — same cadence as the
  // AI Screening page.
  const isRunning = Boolean(state?.running_call_id);
  useEffect(() => {
    if (isRunning && !pollRef.current) {
      pollRef.current = setInterval(load, POLL_MS);
    } else if (!isRunning && pollRef.current) {
      clearInterval(pollRef.current);
      pollRef.current = null;
    }
    return () => {
      if (pollRef.current) { clearInterval(pollRef.current); pollRef.current = null; }
    };
  }, [isRunning, load]);

  if (!allowed) return null;   // RBAC: hidden for anyone who cannot run screening

  const latest = state?.latest_call ?? null;
  const jobs = state?.jobs ?? [];
  const targetJob = jobs[0];
  // A summary exists only for a call the server confirms connected AND finished.
  const hasSummary = Boolean(latest?.is_completed);

  const startCall = async () => {
    if (!state || starting || isRunning) return;
    if (!state.has_phone) {
      toast.warn('This candidate has no phone number, so a call cannot be placed.');
      return;
    }
    if (!targetJob) {
      toast.warn('Add this candidate to a job pipeline first — an AI call needs a JD for its questions.');
      return;
    }
    // Outbound call to a real person: confirm, and name the JD it runs against.
    const res = await showConfirm({
      title: 'Call Candidate',
      text: `Place an AI screening call to ${state.phone} for "${targetJob.title}"?`,
      confirmText: 'Call Now',
      icon: 'question',
    });
    if (!res.isConfirmed) return;

    setStarting(true);
    try {
      const r = (await api.post('/ai-calls/start/', {
        job: targetJob.id,
        candidate_ids: [Number(candidateId)],
      })) as { message?: string; data?: { errors?: string[]; queued?: number } };
      const errors = r.data?.errors ?? [];
      errors.forEach((e) => toast.error(e));
      // Placed directly: the provider request happens synchronously in the view,
      // so this confirms the call was successfully placed and is now dialling.
      if (r.data?.queued) {
        toast.info('Call placed — dialling now…');
      } else if (!errors.length) {
        toast.error('The call was not started. Please try again.');
      }
      await load();
    } catch (e) {
      toast.error(e instanceof Error ? e.message : 'Could not start the call.');
    } finally {
      setStarting(false);
    }
  };

  const openSummary = async () => {
    if (!latest) return;
    setSummaryOpen(true);
    setSummaryLoading(true);
    try {
      const r = (await api.get(`/ai-calls/${latest.call_id}/transcript/`)) as { data?: SummaryData };
      setSummary(r?.data ?? null);
    } catch (e) {
      setSummary(null);
      toast.error(e instanceof Error ? e.message : 'Could not load the call summary.');
    } finally {
      setSummaryLoading(false);
    }
  };

  const badge = latest ? STATUS_BADGES[latest.status] : null;

  return (
    <>
      <span className="inline-flex items-center gap-2">
        <button
          type="button"
          onClick={startCall}
          disabled={starting || isRunning}
          title={
            !state?.has_phone ? 'No phone number on this candidate'
              : isRunning ? 'A call for this candidate is already in progress'
                : targetJob ? `Start an AI screening call for "${targetJob.title}"`
                  : 'Add this candidate to a job pipeline first'
          }
          className="inline-flex items-center gap-1.5 bg-[#0ab39c] hover:bg-[#099885] disabled:opacity-50 disabled:cursor-not-allowed text-white text-xs font-bold px-3 py-1.5 rounded-none cursor-pointer transition"
        >
          <i className={`fa-solid ${starting || isRunning ? 'fa-spinner fa-spin' : 'fa-phone-volume'} text-[11px]`}></i>
          {isRunning ? 'Calling…' : starting ? 'Starting…' : 'Call Candidate'}
        </button>

        {/* Enabled only for a call that actually connected and completed. */}
        <button
          type="button"
          onClick={openSummary}
          disabled={!hasSummary}
          title={hasSummary
            ? 'View the AI call summary'
            : latest
              ? `No call summary available because the call was not completed (${STATUS_BADGES[latest.status]?.label ?? latest.status}).`
              : 'No call summary available'}
          className="inline-flex items-center gap-1.5 border border-[#405189]/30 text-[#405189] dark:text-indigo-300 hover:bg-[#405189]/10 disabled:opacity-40 disabled:cursor-not-allowed text-xs font-bold px-3 py-1.5 rounded-none cursor-pointer transition"
        >
          <i className="fa-solid fa-file-lines text-[11px]"></i>
          Call Summary
        </button>

        {/* Live status of the latest call — exactly what the provider reported */}
        {badge && (
          <span
            title={latest?.error_message || badge.label}
            className={`inline-flex items-center gap-1 text-[10px] font-bold px-2 py-0.5 rounded-none ${badge.cls}`}
          >
            <i className={`fa-solid ${badge.icon} ${badge.pulse ? 'animate-pulse' : ''} text-[9px]`}></i>
            {badge.label}
          </span>
        )}

      </span>

      {/* ===== Call Summary modal ===== */}
      {summaryOpen && (
        <div className="fixed inset-0 z-[200] flex items-center justify-center p-4">
          <div className="fixed inset-0 bg-slate-950/40 dark:bg-slate-950/80 backdrop-blur-sm" onClick={() => setSummaryOpen(false)}></div>
          <div className="bg-white dark:bg-slate-900 border border-slate-200 dark:border-slate-800 w-full max-w-2xl rounded-none relative z-10 shadow-2xl text-slate-800 dark:text-slate-100 flex flex-col max-h-[90vh]">
            <div className="flex items-center justify-between px-6 pt-5 pb-4 border-b border-slate-100 dark:border-slate-800 shrink-0">
              <div className="flex items-center gap-3">
                <div className="w-10 h-10 rounded-none bg-[#0ab39c]/10 text-[#0ab39c] flex items-center justify-center">
                  <i className="fa-solid fa-headset"></i>
                </div>
                <div>
                  <h3 className="text-base font-bold text-slate-900 dark:text-white leading-tight">AI Call Summary</h3>
                  <p className="text-xs text-slate-400 mt-0.5">
                    {summary?.job_title || latest?.job_title || 'AI screening call'}
                  </p>
                </div>
              </div>
              <button
                onClick={() => setSummaryOpen(false)}
                className="w-8 h-8 rounded-none flex items-center justify-center text-slate-400 hover:text-slate-700 dark:hover:text-white hover:bg-slate-100 dark:hover:bg-slate-800 transition cursor-pointer"
              >
                <i className="fa-solid fa-xmark"></i>
              </button>
            </div>

            <div className="px-6 py-4 overflow-y-auto custom-scrollbar flex-1 min-h-0 space-y-4">
              {summaryLoading ? (
                <p className="text-sm text-slate-400 flex items-center gap-2 py-6">
                  <i className="fa-solid fa-spinner fa-spin"></i> Loading call details…
                </p>
              ) : !summary && !latest ? (
                <p className="text-sm text-slate-400 py-6">No call summary available.</p>
              ) : !hasSummary ? (
                /* The call never connected and completed, so there is no result to
                   show. Status/timings still appear so the reason is visible, but
                   no summary, transcript, score or recommendation is rendered. */
                <div className="py-2 space-y-4">
                  <div className="grid grid-cols-2 sm:grid-cols-3 gap-3">
                    {([
                      ['Call Status', (STATUS_BADGES[latest?.status ?? '']?.label) || '—'],
                      ['Call Duration', fmtDuration(latest?.duration ?? null)],
                      ['Call Date & Time', latest?.started_at || '—'],
                    ] as [string, string][]).map(([label, value]) => (
                      <div key={label} className="border border-slate-200 dark:border-slate-800 p-3">
                        <p className="text-[9px] uppercase tracking-wider text-slate-400 font-bold">{label}</p>
                        <p className="text-sm font-bold text-slate-800 dark:text-white mt-1">{value}</p>
                      </div>
                    ))}
                  </div>
                  <p className="text-sm text-slate-600 dark:text-slate-300 border border-amber-200 dark:border-amber-900/40 bg-amber-50/60 dark:bg-amber-950/20 p-3">
                    No call summary available because the call was not completed.
                  </p>
                  {latest?.error_message && (
                    <p className="text-xs text-rose-600 dark:text-rose-400">{latest.error_message}</p>
                  )}
                </div>
              ) : (
                <>
                  {/* Status / duration / date */}
                  <div className="grid grid-cols-2 sm:grid-cols-3 gap-3">
                    {([
                      ['Call Status', (STATUS_BADGES[(summary?.status || latest?.status) ?? '']?.label) || '—'],
                      ['Call Duration', fmtDuration(summary?.duration ?? latest?.duration ?? null)],
                      ['Call Date & Time', (summary?.started_at || latest?.started_at) || '—'],
                    ] as [string, string][]).map(([label, value]) => (
                      <div key={label} className="border border-slate-200 dark:border-slate-800 p-3">
                        <p className="text-[9px] uppercase tracking-wider text-slate-400 font-bold">{label}</p>
                        <p className="text-sm font-bold text-slate-800 dark:text-white mt-1">{value}</p>
                      </div>
                    ))}
                  </div>

                  {/* Outcome / result */}
                  <div>
                    <p className="text-[10px] uppercase tracking-wider font-extrabold text-slate-400 mb-2">AI Outcome</p>
                    <div className="flex flex-wrap items-center gap-2">
                      {(() => {
                        const rec = summary?.evaluation?.recommendation || summary?.recommendation || latest?.recommendation || '';
                        const meta = REC_LABELS[rec];
                        return meta
                          ? <span className={`text-[10px] font-bold px-2 py-0.5 rounded-none ${meta.cls}`}>{meta.label}</span>
                          : <span className="text-xs text-slate-400">Not evaluated</span>;
                      })()}
                      {(summary?.evaluation?.overall_score ?? summary?.score ?? latest?.score) != null && (
                        <span className="text-[10px] font-bold px-2 py-0.5 rounded-none bg-[#405189]/10 text-[#405189] dark:text-indigo-300">
                          Score {summary?.evaluation?.overall_score ?? summary?.score ?? latest?.score}
                        </span>
                      )}
                      {summary?.evaluation?.classification && (
                        <span className="text-[10px] font-bold px-2 py-0.5 rounded-none bg-slate-100 dark:bg-slate-800 text-slate-600 dark:text-slate-300">
                          {summary.evaluation.classification}
                        </span>
                      )}
                    </div>
                  </div>

                  {/* AI summary */}
                  <div>
                    <p className="text-[10px] uppercase tracking-wider font-extrabold text-slate-400 mb-2">AI Call Summary</p>
                    <p className="text-sm text-slate-700 dark:text-slate-300 whitespace-pre-line border border-slate-200 dark:border-slate-800 p-3">
                      {summary?.evaluation?.summary || summary?.summary || latest?.summary || 'No summary returned for this call.'}
                    </p>
                  </div>

                  {(summary?.evaluation?.strengths?.length || summary?.evaluation?.weaknesses?.length) ? (
                    <div className="grid grid-cols-1 sm:grid-cols-2 gap-3">
                      {(['strengths', 'weaknesses'] as const).map((k) => (
                        (summary?.evaluation?.[k]?.length ?? 0) > 0 && (
                          <div key={k}>
                            <p className="text-[10px] uppercase tracking-wider font-extrabold text-slate-400 mb-2">{k}</p>
                            <ul className="text-xs text-slate-600 dark:text-slate-300 list-disc pl-4 space-y-1">
                              {summary!.evaluation![k].map((s, i) => <li key={i}>{s}</li>)}
                            </ul>
                          </div>
                        )
                      ))}
                    </div>
                  ) : null}

                  {/* Transcript — only when the provider returned one */}
                  {(summary?.utterances?.length || summary?.transcript) ? (
                    <div>
                      <p className="text-[10px] uppercase tracking-wider font-extrabold text-slate-400 mb-2">AI Transcript</p>
                      <div className="border border-slate-200 dark:border-slate-800 p-3 max-h-64 overflow-y-auto custom-scrollbar space-y-2">
                        {summary?.utterances?.length ? (
                          summary.utterances.map((u) => (
                            <p key={u.sequence} className="text-xs text-slate-600 dark:text-slate-300">
                              <span className="font-bold text-[#405189] dark:text-indigo-300">{u.speaker}:</span> {u.message}
                            </p>
                          ))
                        ) : (
                          <p className="text-xs text-slate-600 dark:text-slate-300 whitespace-pre-line">{summary?.transcript}</p>
                        )}
                      </div>
                    </div>
                  ) : null}

                  {(summary?.error_message || latest?.error_message) && (
                    <p className="text-xs text-rose-600 dark:text-rose-400">{summary?.error_message || latest?.error_message}</p>
                  )}
                </>
              )}
            </div>

            <div className="flex justify-end px-6 py-4 border-t border-slate-100 dark:border-slate-800 shrink-0">
              <button
                onClick={() => setSummaryOpen(false)}
                className="bg-[#405189] hover:bg-[#364574] text-white text-sm font-semibold px-5 py-2.5 rounded-none shadow-lg transition cursor-pointer"
              >
                Close
              </button>
            </div>
          </div>
        </div>
      )}
    </>
  );
}
