import { useCallback, useEffect, useMemo, useState } from 'react';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { faPenToSquare, faRotateLeft, faRobot } from '@fortawesome/pro-duotone-svg-icons';
import { WizardStep } from './wizard-step';
import { AiRightPane, type AiActorSummary } from './wizard-right-panes';
import { AiForm, emptyAiFormValues, type AiFormValues, type AiProvider } from '@/components/forms/ai-form';
import { Button } from '@/components/base/buttons/button';
import { SlideoutMenu } from '@/components/application/slideout-menus/slideout-menu';
import { EditPatientConfirmModal } from '@/components/modals/edit-patient-confirm-modal';
import { apiClient } from '@/lib/api-client';
import { notify } from '@/lib/toast';
import { useAuth } from '@/providers/auth-provider';
import type { WizardStepComponentProps } from './wizard-step-types';

// AI step (post-prompt-config rework). The middle pane has two sections:
//
//   1. Provider / model / temperature picker — same as before, drives the
//      provider that all actors use under the hood.
//   2. AI personas — list of 7 actor cards, each with name, description,
//      truncated current template, and an Edit button. Edit triggers a
//      confirmation modal warning about unintended consequences, then
//      opens a slideout with the full template + a "variables you can
//      use" reference + Save / Reset.
//
// The right pane shows the same 7 personas as compact "last edited" cards
// so the admin can scan recent activity at a glance.
//
// Backend wiring lives in helix-engage-server/src/config/ai.defaults.ts
// (DEFAULT_AI_PROMPTS) + ai-config.service.ts (renderPrompt / updatePrompt
// / resetPrompt). The 7 service files (widget chat, CC agent helper,
// supervisor, lead enrichment, call insight, call assist, recording
// analysis) all call AiConfigService.renderPrompt(actor, vars) so any
// edit here lands instantly.

type ServerPromptConfig = {
    label: string;
    description: string;
    variables: { key: string; description: string }[];
    template: string;
    defaultTemplate: string;
    lastEditedAt: string | null;
    lastEditedBy: string | null;
};

type ServerAiConfig = {
    provider?: AiProvider;
    model?: string;
    temperature?: number;
    prompts?: Record<string, ServerPromptConfig>;
};

// Display order for the actor cards. Mirrors AI_ACTOR_KEYS in
// ai.defaults.ts so the wizard renders personas in the same order
// admins see them documented elsewhere.
const ACTOR_ORDER = [
    'widgetChat',
    'ccAgentHelper',
    'supervisorChat',
    'leadEnrichment',
    'callInsight',
    'callAssist',
    'recordingAnalysis',
] as const;

const truncate = (s: string, max: number): string =>
    s.length > max ? s.slice(0, max).trimEnd() + '…' : s;

export const WizardStepAi = (props: WizardStepComponentProps) => {
    const { user } = useAuth();
    const [values, setValues] = useState<AiFormValues>(emptyAiFormValues);
    const [prompts, setPrompts] = useState<Record<string, ServerPromptConfig>>({});
    const [loading, setLoading] = useState(true);
    const [saving, setSaving] = useState(false);

    // Edit flow state — three phases:
    //   1. confirmingActor: which actor's Edit button was just clicked
    //      (drives the confirmation modal)
    //   2. editingActor: which actor's slideout is open (only set after
    //      the user confirms past the warning prompt)
    //   3. draftTemplate: the current textarea contents in the slideout
    const [confirmingActor, setConfirmingActor] = useState<string | null>(null);
    const [editingActor, setEditingActor] = useState<string | null>(null);
    const [draftTemplate, setDraftTemplate] = useState('');
    const [savingPrompt, setSavingPrompt] = useState(false);

    const fetchConfig = useCallback(async () => {
        try {
            const data = await apiClient.get<ServerAiConfig>('/api/config/ai', { silent: true });
            setValues({
                provider: data.provider ?? 'openai',
                model: data.model ?? 'gpt-4o-mini',
                temperature: data.temperature != null ? String(data.temperature) : '0.7',
                systemPromptAddendum: '',
            });
            setPrompts(data.prompts ?? {});
        } catch (err) {
            console.error('[wizard/ai] fetch failed', err);
        } finally {
            setLoading(false);
        }
    }, []);

    useEffect(() => {
        fetchConfig();
    }, [fetchConfig]);

    const handleSaveProviderConfig = async () => {
        if (!values.model.trim()) {
            notify.error('Model is required');
            return;
        }
        const temperature = Number(values.temperature);
        setSaving(true);
        try {
            await apiClient.put('/api/config/ai', {
                provider: values.provider,
                model: values.model.trim(),
                temperature: Number.isNaN(temperature) ? 0.7 : Math.min(2, Math.max(0, temperature)),
            });
            notify.success('AI settings saved', 'Provider and model updated.');
            await fetchConfig();
            if (!props.isCompleted) {
                await props.onComplete('ai');
            }
        } catch (err) {
            console.error('[wizard/ai] save provider failed', err);
        } finally {
            setSaving(false);
        }
    };

    // Confirmation modal → slideout flow.
    const handleEditClick = (actor: string) => {
        setConfirmingActor(actor);
    };

    const handleConfirmEdit = () => {
        if (!confirmingActor) return;
        const prompt = prompts[confirmingActor];
        if (!prompt) return;
        setEditingActor(confirmingActor);
        setDraftTemplate(prompt.template);
        setConfirmingActor(null);
    };

    const handleSavePrompt = async (close: () => void) => {
        if (!editingActor) return;
        if (!draftTemplate.trim()) {
            notify.error('Prompt cannot be empty');
            return;
        }
        setSavingPrompt(true);
        try {
            await apiClient.put(`/api/config/ai/prompts/${editingActor}`, {
                template: draftTemplate,
                editedBy: user?.email ?? null,
            });
            notify.success('Prompt updated', `${prompts[editingActor]?.label ?? editingActor} saved`);
            await fetchConfig();
            close();
            setEditingActor(null);
        } catch (err) {
            console.error('[wizard/ai] save prompt failed', err);
        } finally {
            setSavingPrompt(false);
        }
    };

    const handleResetPrompt = async (close: () => void) => {
        if (!editingActor) return;
        setSavingPrompt(true);
        try {
            await apiClient.post(`/api/config/ai/prompts/${editingActor}/reset`);
            notify.success('Prompt reset', `${prompts[editingActor]?.label ?? editingActor} restored to default`);
            await fetchConfig();
            close();
            setEditingActor(null);
        } catch (err) {
            console.error('[wizard/ai] reset prompt failed', err);
        } finally {
            setSavingPrompt(false);
        }
    };

    // Build the right-pane summary entries from the loaded prompts.
    // `isCustom` is true when the template differs from the shipped
    // default OR when the audit fields are populated — either way the
    // admin has touched it.
    const actorSummaries = useMemo<AiActorSummary[]>(() => {
        return ACTOR_ORDER.filter((key) => prompts[key]).map((key) => {
            const p = prompts[key];
            return {
                key,
                label: p.label,
                description: p.description,
                lastEditedAt: p.lastEditedAt,
                isCustom: p.template !== p.defaultTemplate || p.lastEditedAt !== null,
            };
        });
    }, [prompts]);

    const editingPrompt = editingActor ? prompts[editingActor] : null;
    const confirmingLabel = confirmingActor ? prompts[confirmingActor]?.label : '';

    return (
        <WizardStep
            step="ai"
            isCompleted={props.isCompleted}
            isLast={props.isLast}
            onPrev={props.onPrev}
            onNext={props.onNext}
            onMarkComplete={handleSaveProviderConfig}
            onFinish={props.onFinish}
            saving={saving}
            rightPane={<AiRightPane actors={actorSummaries} />}
        >
            {loading ? (
                <p className="text-sm text-tertiary">Loading AI settings…</p>
            ) : (
                <div className="flex flex-col gap-8">
                    <section>
                        <h3 className="mb-3 text-sm font-semibold text-primary">Provider & model</h3>
                        <AiForm value={values} onChange={setValues} />
                    </section>

                    <section>
                        <div className="mb-3 flex items-center justify-between">
                            <h3 className="text-sm font-semibold text-primary">AI personas</h3>
                            <span className="text-xs text-tertiary">
                                {actorSummaries.length} configurable prompts
                            </span>
                        </div>
                        <p className="mb-4 text-xs text-tertiary">
                            Each persona below is a different AI surface in Helix Engage. Editing a
                            prompt changes how that persona sounds and what rules it follows. Defaults
                            are tuned for hospital call centers — only edit if you have a specific
                            reason and can test the result.
                        </p>
                        <ul className="flex flex-col gap-3">
                            {ACTOR_ORDER.map((key) => {
                                const prompt = prompts[key];
                                if (!prompt) return null;
                                const isCustom =
                                    prompt.template !== prompt.defaultTemplate ||
                                    prompt.lastEditedAt !== null;
                                return (
                                    <li
                                        key={key}
                                        className="rounded-xl border border-secondary bg-primary p-4 shadow-xs"
                                    >
                                        <div className="flex items-start gap-3">
                                            <div className="flex size-10 shrink-0 items-center justify-center rounded-full bg-brand-secondary text-brand-secondary">
                                                <FontAwesomeIcon icon={faRobot} className="size-5" />
                                            </div>
                                            <div className="min-w-0 flex-1">
                                                <div className="flex items-start justify-between gap-3">
                                                    <div className="min-w-0">
                                                        <h4 className="truncate text-sm font-semibold text-primary">
                                                            {prompt.label}
                                                        </h4>
                                                        <p className="mt-0.5 text-xs text-tertiary">
                                                            {prompt.description}
                                                        </p>
                                                    </div>
                                                    {isCustom && (
                                                        <span className="shrink-0 rounded-full bg-warning-secondary px-2 py-0.5 text-xs font-medium text-warning-primary">
                                                            Edited
                                                        </span>
                                                    )}
                                                </div>
                                                <p className="mt-3 line-clamp-3 rounded-lg border border-secondary bg-secondary p-3 font-mono text-xs leading-relaxed text-tertiary">
                                                    {truncate(prompt.template, 220)}
                                                </p>
                                                <div className="mt-3 flex justify-end">
                                                    <Button
                                                        size="sm"
                                                        color="secondary"
                                                        onClick={() => handleEditClick(key)}
                                                        iconLeading={({ className }: { className?: string }) => (
                                                            <FontAwesomeIcon
                                                                icon={faPenToSquare}
                                                                className={className}
                                                            />
                                                        )}
                                                    >
                                                        Edit
                                                    </Button>
                                                </div>
                                            </div>
                                        </div>
                                    </li>
                                );
                            })}
                        </ul>
                    </section>
                </div>
            )}

            {/* Confirmation modal — reused from the patient-edit gate. */}
            <EditPatientConfirmModal
                isOpen={confirmingActor !== null}
                onOpenChange={(open) => {
                    if (!open) setConfirmingActor(null);
                }}
                onConfirm={handleConfirmEdit}
                title={`Edit ${confirmingLabel} prompt?`}
                description={
                    <>
                        Modifying this prompt can affect call quality, lead summaries, and supervisor
                        insights in ways that are hard to predict. The defaults are tuned for hospital
                        call centers — only edit if you have a specific reason and can test the
                        result. You can always reset back to default from the editor.
                    </>
                }
                confirmLabel="Yes, edit prompt"
            />

            {/* Slideout editor — only opens after the warning is confirmed. */}
            <SlideoutMenu
                isOpen={editingActor !== null}
                onOpenChange={(open) => {
                    if (!open) setEditingActor(null);
                }}
                isDismissable
            >
                {({ close }) => (
                    <>
                        <SlideoutMenu.Header onClose={close}>
                            <div className="flex items-center gap-3 pr-8">
                                <div className="flex size-10 items-center justify-center rounded-lg bg-brand-secondary">
                                    <FontAwesomeIcon
                                        icon={faRobot}
                                        className="size-5 text-fg-brand-primary"
                                    />
                                </div>
                                <div>
                                    <h2 className="text-lg font-semibold text-primary">
                                        Edit {editingPrompt?.label}
                                    </h2>
                                    <p className="text-sm text-tertiary">
                                        {editingPrompt?.description}
                                    </p>
                                </div>
                            </div>
                        </SlideoutMenu.Header>

                        <SlideoutMenu.Content>
                            <div className="flex flex-col gap-4">
                                <div>
                                    <label className="block text-sm font-medium text-secondary">
                                        Prompt template
                                    </label>
                                    <textarea
                                        value={draftTemplate}
                                        onChange={(e) => setDraftTemplate(e.target.value)}
                                        rows={18}
                                        className="mt-1.5 w-full resize-y rounded-lg border border-secondary bg-primary p-3 font-mono text-xs text-primary outline-none focus:border-brand focus:ring-2 focus:ring-brand-100"
                                    />
                                    <p className="mt-1 text-xs text-tertiary">
                                        Variables wrapped in <code>{'{{double-braces}}'}</code> get
                                        substituted at runtime with live data.
                                    </p>
                                </div>

                                {editingPrompt?.variables && editingPrompt.variables.length > 0 && (
                                    <div className="rounded-lg border border-secondary bg-secondary p-3">
                                        <p className="text-xs font-semibold uppercase tracking-wider text-quaternary">
                                            Variables you can use
                                        </p>
                                        <ul className="mt-2 flex flex-col gap-1.5">
                                            {editingPrompt.variables.map((v) => (
                                                <li key={v.key} className="flex items-start gap-2 text-xs">
                                                    <code className="shrink-0 rounded bg-primary px-1.5 py-0.5 font-mono text-brand-primary">
                                                        {`{{${v.key}}}`}
                                                    </code>
                                                    <span className="text-tertiary">
                                                        {v.description}
                                                    </span>
                                                </li>
                                            ))}
                                        </ul>
                                    </div>
                                )}

                                {editingPrompt?.lastEditedAt && (
                                    <p className="text-xs text-tertiary">
                                        Last edited{' '}
                                        {new Date(editingPrompt.lastEditedAt).toLocaleString()}
                                        {editingPrompt.lastEditedBy && ` by ${editingPrompt.lastEditedBy}`}
                                    </p>
                                )}
                            </div>
                        </SlideoutMenu.Content>

                        <SlideoutMenu.Footer>
                            <div className="flex items-center justify-between gap-3">
                                <Button
                                    size="md"
                                    color="link-gray"
                                    isDisabled={savingPrompt}
                                    onClick={() => handleResetPrompt(close)}
                                    iconLeading={({ className }: { className?: string }) => (
                                        <FontAwesomeIcon icon={faRotateLeft} className={className} />
                                    )}
                                >
                                    Reset to default
                                </Button>
                                <div className="flex items-center gap-3">
                                    <Button
                                        size="md"
                                        color="secondary"
                                        isDisabled={savingPrompt}
                                        onClick={close}
                                    >
                                        Cancel
                                    </Button>
                                    <Button
                                        size="md"
                                        color="primary"
                                        isLoading={savingPrompt}
                                        showTextWhileLoading
                                        onClick={() => handleSavePrompt(close)}
                                    >
                                        {savingPrompt ? 'Saving…' : 'Save prompt'}
                                    </Button>
                                </div>
                            </div>
                        </SlideoutMenu.Footer>
                    </>
                )}
            </SlideoutMenu>
        </WizardStep>
    );
};
