import { useCallback, useEffect, useMemo, useState } from 'react';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { faHeadset, faTrash } from '@fortawesome/pro-duotone-svg-icons';
import { WizardStep } from './wizard-step';
import { TelephonyRightPane, type SipSeatSummary } from './wizard-right-panes';
import { Select } from '@/components/base/select/select';
import { Button } from '@/components/base/buttons/button';
import { apiClient } from '@/lib/api-client';
import { notify } from '@/lib/toast';
import type { WizardStepComponentProps } from './wizard-step-types';

// Telephony step (post-3-pane rework). The middle pane is now an
// assign/unassign editor: pick a SIP seat, pick a workspace member,
// click Assign — or pick an already-mapped seat and click Unassign.
// The right pane shows the live current state (read-only mapping
// summary). Editing here calls updateAgent to set/clear
// workspaceMemberId, then refetches.
//
// SIP seats themselves are pre-provisioned by onboard-hospital.sh
// (see step 5b) — admins can't add or delete seats from this UI,
// only link them to people. To add a new seat, contact support.

type AgentRow = {
    id: string;
    name: string | null;
    sipExtension: string | null;
    ozonetelAgentId: string | null;
    workspaceMemberId: string | null;
    workspaceMember: {
        id: string;
        name: { firstName: string | null; lastName: string | null } | null;
        userEmail: string;
    } | null;
};

type WorkspaceMemberRow = {
    id: string;
    userEmail: string;
    name: { firstName: string | null; lastName: string | null } | null;
};

const AI_EMAIL_SUFFIX = '@ai.fortytwo.local';

const memberDisplayName = (m: {
    name: { firstName: string | null; lastName: string | null } | null;
    userEmail: string;
}): string => {
    const first = m.name?.firstName?.trim() ?? '';
    const last = m.name?.lastName?.trim() ?? '';
    const full = `${first} ${last}`.trim();
    return full.length > 0 ? full : m.userEmail;
};

export const WizardStepTelephony = (props: WizardStepComponentProps) => {
    const [agents, setAgents] = useState<AgentRow[]>([]);
    const [members, setMembers] = useState<WorkspaceMemberRow[]>([]);
    const [loading, setLoading] = useState(true);
    const [saving, setSaving] = useState(false);
    // Editor state — which seat is selected, which member to assign.
    const [selectedSeatId, setSelectedSeatId] = useState<string>('');
    const [selectedMemberId, setSelectedMemberId] = useState<string>('');

    const fetchData = useCallback(async () => {
        try {
            const data = await apiClient.graphql<{
                agents: { edges: { node: AgentRow }[] };
                workspaceMembers: { edges: { node: WorkspaceMemberRow }[] };
            }>(
                `{
                    agents(first: 100) {
                        edges { node {
                            id name sipExtension ozonetelAgentId workspaceMemberId
                            workspaceMember { id name { firstName lastName } userEmail }
                        } }
                    }
                    workspaceMembers(first: 200) {
                        edges { node {
                            id userEmail name { firstName lastName }
                        } }
                    }
                }`,
                undefined,
                { silent: true },
            );
            setAgents(data.agents.edges.map((e) => e.node));
            setMembers(
                data.workspaceMembers.edges
                    .map((e) => e.node)
                    .filter((m) => !m.userEmail.endsWith(AI_EMAIL_SUFFIX)),
            );
        } catch (err) {
            console.error('[wizard/telephony] fetch failed', err);
        } finally {
            setLoading(false);
        }
    }, []);

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

    // Map every agent to a SipSeatSummary for the right pane. Single
    // source of truth — both panes read from `agents`.
    const seatSummaries = useMemo<SipSeatSummary[]>(
        () =>
            agents.map((a) => ({
                id: a.id,
                sipExtension: a.sipExtension,
                ozonetelAgentId: a.ozonetelAgentId,
                workspaceMember: a.workspaceMember,
            })),
        [agents],
    );

    // Pre-compute lookups for the editor — which member already owns
    // each seat, and which members are already taken (so the dropdown
    // can hide them).
    const takenMemberIds = useMemo(
        () =>
            new Set(
                agents
                    .filter((a) => a.workspaceMemberId !== null)
                    .map((a) => a.workspaceMemberId!),
            ),
        [agents],
    );

    const seatItems = useMemo(
        () =>
            agents.map((a) => ({
                id: a.id,
                label: `Ext ${a.sipExtension ?? '—'}`,
                supportingText: a.workspaceMember
                    ? `Currently: ${memberDisplayName(a.workspaceMember)}`
                    : 'Unassigned',
            })),
        [agents],
    );

    // Members dropdown — when a seat is selected and the seat is
    // currently mapped, force the member field to show the current
    // owner so the admin can see who they're displacing. When seat
    // is unassigned, only show free members (the takenMemberIds
    // filter).
    const memberItems = useMemo(() => {
        const selectedSeat = agents.find((a) => a.id === selectedSeatId);
        const currentOwnerId = selectedSeat?.workspaceMemberId ?? null;
        return members
            .filter((m) => m.id === currentOwnerId || !takenMemberIds.has(m.id))
            .map((m) => ({
                id: m.id,
                label: memberDisplayName(m),
                supportingText: m.userEmail,
            }));
    }, [members, agents, selectedSeatId, takenMemberIds]);

    // When the admin picks a seat, default the member dropdown to
    // whoever currently owns it (if anyone) so Unassign just works.
    useEffect(() => {
        if (!selectedSeatId) {
            setSelectedMemberId('');
            return;
        }
        const seat = agents.find((a) => a.id === selectedSeatId);
        setSelectedMemberId(seat?.workspaceMemberId ?? '');
    }, [selectedSeatId, agents]);

    const selectedSeat = agents.find((a) => a.id === selectedSeatId);
    const isCurrentlyMapped = selectedSeat?.workspaceMemberId !== null && selectedSeat?.workspaceMemberId !== undefined;

    const updateSeat = async (seatId: string, workspaceMemberId: string | null) => {
        setSaving(true);
        try {
            await apiClient.graphql(
                `mutation UpdateAgent($id: UUID!, $data: AgentUpdateInput!) {
                    updateAgent(id: $id, data: $data) { id workspaceMemberId }
                }`,
                { id: seatId, data: { workspaceMemberId } },
            );
            await fetchData();
            // Mark the step complete on first successful action so
            // the wizard can advance. Subsequent edits don't re-mark.
            if (!props.isCompleted) {
                await props.onComplete('telephony');
            }
            // Clear editor selection so the admin starts the next
            // assign from scratch.
            setSelectedSeatId('');
            setSelectedMemberId('');
        } catch (err) {
            console.error('[wizard/telephony] updateAgent failed', err);
        } finally {
            setSaving(false);
        }
    };

    const handleAssign = () => {
        if (!selectedSeatId || !selectedMemberId) {
            notify.error('Pick a seat and a member to assign');
            return;
        }
        updateSeat(selectedSeatId, selectedMemberId);
    };

    const handleUnassign = () => {
        if (!selectedSeatId) return;
        updateSeat(selectedSeatId, null);
    };

    const pretendCompleted = props.isCompleted || agents.some((a) => a.workspaceMemberId !== null);

    return (
        <WizardStep
            step="telephony"
            isCompleted={pretendCompleted}
            isLast={props.isLast}
            onPrev={props.onPrev}
            onNext={props.onNext}
            onMarkComplete={async () => {
                if (!props.isCompleted) {
                    await props.onComplete('telephony');
                }
                props.onAdvance();
            }}
            onFinish={props.onFinish}
            saving={saving}
            rightPane={<TelephonyRightPane seats={seatSummaries} />}
        >
            {loading ? (
                <p className="text-sm text-tertiary">Loading SIP seats…</p>
            ) : agents.length === 0 ? (
                <div className="rounded-lg border border-secondary bg-secondary p-6 text-sm text-tertiary">
                    <p className="font-medium text-primary">No SIP seats configured</p>
                    <p className="mt-1">
                        This hospital has no pre-provisioned agent profiles. Contact support to
                        add SIP seats, then come back to finish setup.
                    </p>
                </div>
            ) : (
                <div className="flex flex-col gap-5">
                    <div className="rounded-lg border border-secondary bg-secondary p-4 text-xs text-tertiary">
                        <p>
                            Pick a SIP seat and assign it to a workspace member. To free up a seat,
                            select it and click <b>Unassign</b>. The right pane shows the live
                            mapping — what you change here updates there immediately.
                        </p>
                    </div>

                    <Select
                        label="SIP seat"
                        placeholder="Select a seat"
                        items={seatItems}
                        selectedKey={selectedSeatId || null}
                        onSelectionChange={(key) => setSelectedSeatId((key as string) || '')}
                    >
                        {(item) => (
                            <Select.Item
                                id={item.id}
                                label={item.label}
                                supportingText={item.supportingText}
                            />
                        )}
                    </Select>

                    <Select
                        label="Workspace member"
                        placeholder={
                            !selectedSeatId
                                ? 'Pick a seat first'
                                : memberItems.length === 0
                                ? 'No available members'
                                : 'Select a member'
                        }
                        isDisabled={!selectedSeatId || memberItems.length === 0}
                        items={memberItems}
                        selectedKey={selectedMemberId || null}
                        onSelectionChange={(key) => setSelectedMemberId((key as string) || '')}
                    >
                        {(item) => (
                            <Select.Item
                                id={item.id}
                                label={item.label}
                                supportingText={item.supportingText}
                            />
                        )}
                    </Select>

                    <div className="flex items-center justify-end gap-3">
                        {isCurrentlyMapped && (
                            <Button
                                color="secondary-destructive"
                                size="md"
                                isDisabled={saving}
                                onClick={handleUnassign}
                                iconLeading={({ className }: { className?: string }) => (
                                    <FontAwesomeIcon icon={faTrash} className={className} />
                                )}
                            >
                                Unassign
                            </Button>
                        )}
                        <Button
                            color="primary"
                            size="md"
                            isDisabled={saving || !selectedSeatId || !selectedMemberId}
                            onClick={handleAssign}
                            iconLeading={({ className }: { className?: string }) => (
                                <FontAwesomeIcon icon={faHeadset} className={className} />
                            )}
                        >
                            {selectedSeat?.workspaceMemberId === selectedMemberId
                                ? 'Already assigned'
                                : isCurrentlyMapped
                                ? 'Reassign'
                                : 'Assign'}
                        </Button>
                    </div>
                </div>
            )}
        </WizardStep>
    );
};
