'use client';

/**
 * DoctorCoachPanel — the chat surface for the Doctor Coach widget.
 *
 * Intentional simplifications vs. patient CoachPanel:
 *   - Single-tab (chat only). No settings tab — doctors don't configure
 *     reminders, push notifications, or seasonal alerts through the coach.
 *   - No notification permission prompt — doctors' workflow is chat-on-demand;
 *     they receive clinical notifications through the main notification rail.
 *   - proposedActions render doctor-specific deep links (view EMR, open
 *     SOAP editor, schedule follow-up) instead of patient-side links.
 *   - Header label: "Doctor Coach · your clinical assistant"
 *
 * The conversation id is held in component state; on close the state is
 * kept so the next open resumes the same thread (same as patient side).
 */

import { useCallback, useEffect, useRef, useState } from 'react';
import {
  AlertTriangle,
  Sparkles,
  X,
} from 'lucide-react';

import { doctorCoachClient, DoctorCoachClientError } from '@/lib/doctor-coach-client';
import type {
  DoctorCoachConversation,
  DoctorCoachMessage,
  DoctorCoachRefusalReason,
} from '@/lib/doctor-coach-types';

import { SehatAvatar, type CoachAvatarState } from './sehat-avatar';

interface DoctorCoachPanelProps {
  onClose: () => void;
}

const REFUSAL_TITLE: Record<DoctorCoachRefusalReason, string> = {
  cross_user: "Outside your allocated patients",
  medical_advice: "That needs a clinical decision",
  out_of_scope: "Outside my scope",
  unsafe: "I can't help with that",
  pii_leak: "Privacy",
};

export function DoctorCoachPanel({ onClose }: DoctorCoachPanelProps) {
  const [conversation, setConversation] = useState<DoctorCoachConversation | null>(null);
  const [composer, setComposer] = useState('');
  const [sending, setSending] = useState(false);
  const [error, setError] = useState<string | null>(null);
  const [avatarState, setAvatarState] = useState<CoachAvatarState>('idle');

  const scrollRef = useRef<HTMLDivElement>(null);

  // Start a new conversation on first open. Locale defaults to 'en' — doctors
  // can switch to Urdu by simply writing in Urdu (the model will mirror it).
  useEffect(() => {
    let cancelled = false;
    void (async () => {
      try {
        const c = await doctorCoachClient.start({ locale: 'en' });
        if (!cancelled) setConversation(c);
      } catch (e) {
        if (cancelled) return;
        setError(coachError(e));
      }
    })();
    return () => {
      cancelled = true;
    };
  }, []);

  // Scroll to bottom whenever new messages arrive.
  useEffect(() => {
    const node = scrollRef.current;
    if (node) node.scrollTop = node.scrollHeight;
  }, [conversation?.messages.length]);

  const send = useCallback(
    async (text: string) => {
      const trimmed = text.trim();
      if (!trimmed || !conversation) return;
      setSending(true);
      setError(null);
      setAvatarState('thinking');

      // Optimistic local user turn.
      const optimistic: DoctorCoachMessage = {
        id: `local-${Date.now()}`,
        role: 'user',
        content: trimmed,
        createdAt: new Date().toISOString(),
      };
      setConversation((prev) =>
        prev ? { ...prev, messages: [...prev.messages, optimistic] } : prev,
      );
      setComposer('');

      try {
        const turn = await doctorCoachClient.send(conversation.id, trimmed);
        setConversation((prev) =>
          prev
            ? { ...prev, messages: [...prev.messages, turn.message] }
            : prev,
        );
        setAvatarState(turn.message.escalate ? 'idle' : 'speaking');
        setTimeout(() => setAvatarState('idle'), 1600);
      } catch (e) {
        setError(coachError(e));
        setAvatarState('idle');
      } finally {
        setSending(false);
      }
    },
    [conversation],
  );

  return (
    <div
      role="dialog"
      aria-label="Doctor Coach"
      className="fixed inset-x-0 bottom-0 z-[70] flex justify-end sm:inset-y-0 sm:right-4 sm:left-auto sm:top-auto sm:bottom-4"
    >
      <div className="flex h-[80vh] w-full max-w-md flex-col overflow-hidden rounded-t-3xl border border-warmSurface-border bg-warmSurface-card shadow-2xl sm:rounded-3xl">
        {/* Header — single panel, no tab bar */}
        <div className="flex items-center justify-between border-b border-warmSurface-border bg-gradient-to-br from-coral-50/70 to-warmSurface-card px-4 py-3">
          <div className="flex items-center gap-3">
            <SehatAvatar state={avatarState} size="sm" />
            <div>
              <p className="font-display text-sm font-bold text-ink-1">
                Doctor Coach
              </p>
              <p className="text-[11px] text-ink-3">
                your clinical assistant · output is always a draft
              </p>
            </div>
          </div>
          <button
            type="button"
            onClick={onClose}
            aria-label="Close Doctor Coach"
            className="rounded-lg p-2 text-ink-2 hover:bg-warmSurface-bg"
          >
            <X className="h-4 w-4" />
          </button>
        </div>

        {/* Message list */}
        <div
          ref={scrollRef}
          className="flex-1 space-y-3 overflow-y-auto px-4 py-3"
        >
          {!conversation ? (
            <p className="text-center text-sm text-ink-3">Connecting…</p>
          ) : (
            conversation.messages.map((m) => (
              <MessageBubble
                key={m.id}
                message={m}
                onSuggestedReply={(text) => void send(text)}
              />
            ))
          )}
          {sending ? (
            <p className="text-center text-xs text-ink-3">
              Doctor Coach is thinking…
            </p>
          ) : null}
          {error ? (
            <p className="rounded-lg bg-coral-50 px-3 py-2 text-sm text-coral-700">
              {error}
            </p>
          ) : null}
        </div>

        {/* Composer */}
        <Composer
          disabled={sending || !conversation}
          value={composer}
          onChange={setComposer}
          onSubmit={() => void send(composer)}
        />
      </div>
    </div>
  );
}

// ----------------------------------------------------------------------
// Sub-components
// ----------------------------------------------------------------------

function MessageBubble({
  message,
  onSuggestedReply,
}: {
  message: DoctorCoachMessage;
  onSuggestedReply: (text: string) => void;
}) {
  const isUser = message.role === 'user';
  const refusal = message.refusalReason;

  if (isUser) {
    return (
      <div className="flex justify-end">
        <div className="max-w-[85%] rounded-2xl rounded-br-md bg-brand-600 px-3 py-2 text-sm text-white shadow-sm">
          {message.content}
        </div>
      </div>
    );
  }

  return (
    <div className="flex flex-col items-start gap-1.5">
      <div
        className={[
          'max-w-[85%] rounded-2xl rounded-bl-md px-3 py-2 text-sm shadow-sm',
          refusal
            ? 'border border-coral-200 bg-coral-50 text-coral-900'
            : 'bg-warmSurface-bg text-ink-1',
        ].join(' ')}
      >
        {refusal ? (
          <p className="mb-1 inline-flex items-center gap-1 text-[11px] font-semibold uppercase tracking-wider text-coral-700">
            <AlertTriangle className="h-3 w-3" />
            {REFUSAL_TITLE[refusal]}
          </p>
        ) : null}
        {/* Render content preserving newlines from SOAP drafts */}
        <p className="whitespace-pre-wrap leading-relaxed">{message.content}</p>
      </div>

      {message.escalate ? (
        <div className="rounded-lg bg-coral-100 px-3 py-1.5 text-[12px] font-semibold text-coral-800">
          ⚠ Escalate — this patient may need urgent senior review or referral.
        </div>
      ) : null}

      {message.suggestedReplies && message.suggestedReplies.length > 0 ? (
        <div className="flex flex-wrap gap-1.5 pt-1">
          {message.suggestedReplies.map((r) => (
            <button
              key={r}
              type="button"
              onClick={() => onSuggestedReply(r)}
              className="rounded-full border border-brand-200 bg-warmSurface-card px-2.5 py-1 text-[12px] font-medium text-brand-700 hover:bg-brand-50"
            >
              {r}
            </button>
          ))}
        </div>
      ) : null}

      {message.proposedActions && message.proposedActions.length > 0 ? (
        <div className="flex flex-wrap gap-1.5 pt-1">
          {message.proposedActions.map((a, i) => (
            <a
              key={`${a.kind}-${i}`}
              href={hrefForAction(a.kind, a.payload)}
              className="inline-flex items-center gap-1 rounded-full bg-brand-600 px-2.5 py-1 text-[12px] font-semibold text-white shadow-sm hover:bg-brand-700"
            >
              <Sparkles className="h-3 w-3" />
              {a.label}
            </a>
          ))}
        </div>
      ) : null}
    </div>
  );
}

function Composer({
  value,
  onChange,
  onSubmit,
  disabled,
}: {
  value: string;
  onChange: (v: string) => void;
  onSubmit: () => void;
  disabled: boolean;
}) {
  return (
    <form
      onSubmit={(e) => {
        e.preventDefault();
        onSubmit();
      }}
      className="flex items-end gap-2 border-t border-warmSurface-border bg-warmSurface-card p-3"
    >
      <textarea
        value={value}
        onChange={(e) => onChange(e.target.value)}
        onKeyDown={(e) => {
          if (e.key === 'Enter' && !e.shiftKey) {
            e.preventDefault();
            onSubmit();
          }
        }}
        rows={1}
        placeholder="Ask for a SOAP draft, EMR summary, or clinical reference…"
        className="min-h-[40px] max-h-32 flex-1 resize-none rounded-2xl border border-warmSurface-border bg-warmSurface-bg px-3 py-2 text-sm text-ink-1 focus:border-brand-400 focus:outline-none focus:ring-1 focus:ring-brand-300"
      />
      <button
        type="submit"
        disabled={disabled || !value.trim()}
        className="rounded-2xl bg-brand-600 px-3 py-2 text-sm font-semibold text-white shadow-sm transition-colors hover:bg-brand-700 disabled:cursor-not-allowed disabled:opacity-50"
      >
        Send
      </button>
    </form>
  );
}

// ----------------------------------------------------------------------
// helpers
// ----------------------------------------------------------------------

function coachError(e: unknown): string {
  if (e instanceof DoctorCoachClientError) return e.message;
  if (e instanceof Error) return e.message;
  return 'Something went wrong — please try again.';
}

/**
 * Map a doctor coach action kind to a portal deep-link URL.
 *
 * Payloads are schemaless so we extract what we know and fall back to
 * the base route gracefully. The UI's router handles the rest.
 */
function hrefForAction(
  kind: DoctorCoachMessage['proposedActions'] extends infer A
    ? A extends Array<infer X>
      ? X extends { kind: infer K }
        ? K
        : never
      : never
    : never,
  payload?: Record<string, unknown>,
): string {
  switch (kind) {
    case 'draft_soap': {
      const apptId =
        typeof payload?.appointmentId === 'string' ? payload.appointmentId : '';
      return apptId ? `/appointments/${apptId}#soap` : '/appointments';
    }
    case 'view_patient_emr': {
      const userId =
        typeof payload?.patientUserId === 'string' ? payload.patientUserId : '';
      return userId ? `/patients/${userId}` : '/appointments';
    }
    case 'schedule_followup': {
      const apptId =
        typeof payload?.appointmentId === 'string' ? payload.appointmentId : '';
      return apptId ? `/appointments/${apptId}#follow-up` : '/appointments';
    }
    default:
      return '#';
  }
}
