import { useEffect, useMemo, useState, useRef, useCallback } from 'react';
import { faMagnifyingGlass, faPlay, faPause, faSparkles } from '@fortawesome/pro-duotone-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { faIcon } from '@/lib/icon-wrapper';
import type { SortDescriptor } from 'react-aria-components';

const SearchLg = faIcon(faMagnifyingGlass);
import { Badge } from '@/components/base/badges/badges';
import { Input } from '@/components/base/input/input';
import { Table } from '@/components/application/table/table';
import { PaginationPageDefault } from '@/components/application/pagination/pagination';
import { PageHeader } from '@/components/layout/page-header';
import { ColumnToggle, useColumnVisibility } from '@/components/application/table/column-toggle';
import { PhoneActionCell } from '@/components/call-desk/phone-action-cell';
import { RecordingAnalysisSlideout } from '@/components/call-desk/recording-analysis';
import { apiClient } from '@/lib/api-client';
import { getSocket } from '@/lib/socket';
import { formatPhone, formatDateOrdinal, formatTimeOnly } from '@/lib/format';
import { computeSlaStatus } from '@/lib/scoring';
import { cx } from '@/utils/cx';

type RecordingRecord = {
    id: string;
    createdAt: string | null;
    direction: string | null;
    callStatus: string | null;
    callerNumber: { primaryPhoneNumber: string } | null;
    agentName: string | null;
    agent: { id: string; name: string; ozonetelAgentId: string } | null;
    startedAt: string | null;
    durationSec: number | null;
    disposition: string | null;
    recording: { primaryLinkUrl: string; primaryLinkLabel: string } | null;
    sla: number | null;
};

const QUERY = `{ calls(first: 200, orderBy: [{ startedAt: DescNullsLast }]) { edges { node {
    id createdAt direction callStatus callerNumber { primaryPhoneNumber }
    agentName agent { id name ozonetelAgentId }
    startedAt durationSec disposition sla
    recording { primaryLinkUrl primaryLinkLabel }
} } } }`;

const PAGE_SIZE = 15;


const formatDuration = (sec: number | null): string => {
    if (!sec) return '—';
    const m = Math.floor(sec / 60);
    const s = sec % 60;
    return `${m}:${s.toString().padStart(2, '0')}`;
};

const getCallSla = (call: RecordingRecord): { percent: number; status: 'low' | 'medium' | 'high' | 'critical' } | null => {
    if (call.sla == null) return null;
    const percent = Math.round(call.sla);
    return { percent, status: computeSlaStatus(percent) };
};

const RecordingPlayer = ({ url }: { url: string }) => {
    const audioRef = useRef<HTMLAudioElement>(null);
    const [playing, setPlaying] = useState(false);

    const toggle = () => {
        if (!audioRef.current) return;
        if (playing) { audioRef.current.pause(); } else { audioRef.current.play(); }
        setPlaying(!playing);
    };

    return (
        <div className="flex items-center gap-2">
            <button onClick={toggle} className="flex size-7 items-center justify-center rounded-full bg-brand-solid text-white hover:opacity-90 transition duration-100 ease-linear">
                <FontAwesomeIcon icon={playing ? faPause : faPlay} className="size-3" />
            </button>
            <audio ref={audioRef} src={url} onEnded={() => setPlaying(false)} />
        </div>
    );
};

const columnDefs = [
    { id: 'agent', label: 'Agent', defaultVisible: true, allowsSorting: true, isRowHeader: true },
    { id: 'caller', label: 'Caller', defaultVisible: true },
    { id: 'ai', label: 'AI', defaultVisible: true },
    { id: 'type', label: 'Type', defaultVisible: true },
    { id: 'sla', label: 'SLA', defaultVisible: true, allowsSorting: true },
    { id: 'dateTime', label: 'Date & Time', defaultVisible: true, allowsSorting: true },
    { id: 'duration', label: 'Duration', defaultVisible: true, allowsSorting: true },
    { id: 'disposition', label: 'Disposition', defaultVisible: true },
    { id: 'recording', label: 'Recording', defaultVisible: true },
];

export const CallRecordingsPage = () => {
    const [calls, setCalls] = useState<RecordingRecord[]>([]);
    const [loading, setLoading] = useState(true);
    const [search, setSearch] = useState('');
    const [currentPage, setCurrentPage] = useState(1);
    const [slideoutCallId, setSlideoutCallId] = useState<string | null>(null);
    const [sortDescriptor, setSortDescriptor] = useState<SortDescriptor>({ column: 'dateTime', direction: 'descending' });
    const { visibleColumns, toggle: toggleColumn } = useColumnVisibility(columnDefs);

    // Dynamic columns for React Aria — filter by visibility, pass as prop
    const activeColumns = useMemo(
        () => columnDefs.filter(c => visibleColumns.has(c.id)),
        [visibleColumns],
    );

    // Cell renderer — lives inside the component so it can access setSlideoutCallId
    const renderRecordingCell = useCallback((call: RecordingRecord, colId: string) => {
        const phone = call.callerNumber?.primaryPhoneNumber ?? '';
        const dirLabel = call.direction === 'INBOUND' ? 'In' : 'Out';
        const dirColor: 'blue' | 'brand' = call.direction === 'INBOUND' ? 'blue' : 'brand';
        switch (colId) {
            case 'agent':
                return <span className="text-sm text-primary">{call.agent?.name ?? call.agentName ?? '—'}</span>;
            case 'caller':
                return phone
                    ? <PhoneActionCell phoneNumber={phone} displayNumber={formatPhone({ number: phone, callingCode: '+91' })} />
                    : <span className="text-xs text-quaternary">—</span>;
            case 'ai':
                return (
                    <span
                        role="button"
                        tabIndex={0}
                        onPointerDown={(e) => {
                            e.stopPropagation();
                            let longPressed = false;
                            const timer = setTimeout(() => {
                                longPressed = true;
                                window.dispatchEvent(new CustomEvent('maint:trigger', { detail: 'clearAnalysisCache' }));
                            }, 1000);
                            const up = () => { clearTimeout(timer); if (!longPressed) setSlideoutCallId(call.id); };
                            document.addEventListener('pointerup', up, { once: true });
                        }}
                        className="inline-flex items-center gap-1 rounded-full bg-brand-primary px-2.5 py-1 text-xs font-semibold text-brand-secondary hover:bg-brand-secondary hover:text-white cursor-pointer transition duration-100 ease-linear"
                        title="AI Analysis (long-press to regenerate)"
                    >
                        <FontAwesomeIcon icon={faSparkles} className="size-3" />
                        AI
                    </span>
                );
            case 'type':
                return <Badge size="sm" color={dirColor} type="pill-color">{dirLabel}</Badge>;
            case 'sla': {
                const sla = getCallSla(call);
                if (!sla) return <span className="text-xs text-quaternary">—</span>;
                return (
                    <span className="inline-flex items-center gap-1.5 text-xs font-medium">
                        <span className={cx('size-2 rounded-full',
                            sla.status === 'low' && 'bg-success-solid',
                            sla.status === 'medium' && 'bg-warning-solid',
                            sla.status === 'high' && 'bg-error-solid',
                            sla.status === 'critical' && 'bg-error-solid animate-pulse',
                        )} />
                        <span className="text-secondary">{sla.percent}%</span>
                    </span>
                );
            }
            case 'dateTime':
                return call.startedAt ? (
                    <div>
                        <span className="text-sm text-primary">{formatDateOrdinal(call.startedAt)}</span>
                        <span className="block text-xs text-tertiary">{formatTimeOnly(call.startedAt)}</span>
                    </div>
                ) : <span className="text-xs text-quaternary">—</span>;
            case 'duration':
                return <span className="text-sm text-primary">{formatDuration(call.durationSec)}</span>;
            case 'disposition':
                return call.disposition
                    ? <Badge size="sm" color="gray" type="pill-color">{call.disposition.replace(/_/g, ' ').toLowerCase().replace(/\b\w/g, c => c.toUpperCase())}</Badge>
                    : <span className="text-xs text-quaternary">—</span>;
            case 'recording':
                return call.recording?.primaryLinkUrl
                    ? <RecordingPlayer url={call.recording.primaryLinkUrl} />
                    : null;
            default:
                return null;
        }
    }, []);

    const fetchRecordings = useCallback(() => {
        apiClient.graphql<{ calls: { edges: Array<{ node: RecordingRecord }> } }>(QUERY, undefined, { silent: true })
            .then(data => {
                const withRecordings = data.calls.edges
                    .map(e => e.node)
                    .filter(c => c.recording?.primaryLinkUrl);
                setCalls(withRecordings);
            })
            .catch(() => {})
            .finally(() => setLoading(false));
    }, []);

    useEffect(() => {
        fetchRecordings();

        // Listen for real-time call created events via WebSocket
        const socket = getSocket();
        if (!socket.connected) socket.connect();
        socket.emit('supervisor:register');
        const handleCallCreated = () => fetchRecordings();
        socket.on('call:created', handleCallCreated);

        return () => {
            socket.off('call:created', handleCallCreated);
        };
    }, [fetchRecordings]);

    const filtered = useMemo(() => {
        let result = calls;
        if (search.trim()) {
            const q = search.toLowerCase();
            result = result.filter(c =>
                (c.agent?.name ?? c.agentName ?? '').toLowerCase().includes(q) ||
                (c.callerNumber?.primaryPhoneNumber ?? '').includes(q) ||
                (c.disposition ?? '').toLowerCase().includes(q),
            );
        }
        // Sort
        if (sortDescriptor.column) {
            const dir = sortDescriptor.direction === 'ascending' ? 1 : -1;
            result = [...result].sort((a, b) => {
                switch (sortDescriptor.column) {
                    case 'agent': return (a.agent?.name ?? a.agentName ?? '').localeCompare(b.agent?.name ?? b.agentName ?? '') * dir;
                    case 'dateTime': {
                        const ta = a.startedAt ? new Date(a.startedAt).getTime() : 0;
                        const tb = b.startedAt ? new Date(b.startedAt).getTime() : 0;
                        return (ta - tb) * dir;
                    }
                    case 'duration': return ((a.durationSec ?? 0) - (b.durationSec ?? 0)) * dir;
                    case 'sla': return ((a.sla ?? 0) - (b.sla ?? 0)) * dir;
                    default: return 0;
                }
            });
        }
        return result;
    }, [calls, search, sortDescriptor]);

    const totalPages = Math.max(1, Math.ceil(filtered.length / PAGE_SIZE));
    const pagedRows = filtered.slice((currentPage - 1) * PAGE_SIZE, currentPage * PAGE_SIZE);

    const handleSearch = (val: string) => { setSearch(val); setCurrentPage(1); };

    return (
        <div className="flex flex-1 flex-col overflow-hidden">
            <PageHeader
                title="Call Recordings"
                badge={filtered.length}
                infoText="All call recordings with AI analysis, dispositions, and playback."
                controls={
                    <>
                        <ColumnToggle columns={columnDefs} visibleColumns={visibleColumns} onToggle={toggleColumn} />
                        <div className="w-56">
                            <Input placeholder="Search agent, phone, disposition..." icon={SearchLg} size="sm" value={search} onChange={handleSearch} />
                        </div>
                    </>
                }
            />

                {/* Table */}
                <div className="flex flex-1 flex-col min-h-0 overflow-hidden px-4 pt-3">
                    {loading ? (
                        <div className="flex items-center justify-center py-12">
                            <p className="text-sm text-tertiary">Loading recordings...</p>
                        </div>
                    ) : filtered.length === 0 ? (
                        <div className="flex items-center justify-center py-12">
                            <p className="text-sm text-quaternary">{search ? 'No matching recordings' : 'No call recordings found'}</p>
                        </div>
                    ) : (
                        <div className="flex flex-1 flex-col min-h-0 overflow-auto">
                            <Table key={Array.from(visibleColumns).sort().join(',')} size="sm" sortDescriptor={sortDescriptor} onSortChange={setSortDescriptor}>
                                <Table.Header columns={activeColumns}>
                                    {(col) => (
                                        <Table.Head
                                            key={col.id}
                                            id={col.id}
                                            label={col.label}
                                            isRowHeader={col.isRowHeader}
                                            allowsSorting={col.allowsSorting}
                                        />
                                    )}
                                </Table.Header>
                                <Table.Body items={pagedRows}>
                                    {(call) => (
                                        <Table.Row id={call.id} columns={activeColumns} className="group/row">
                                            {(col) => (
                                                <Table.Cell key={col.id}>
                                                    {renderRecordingCell(call, col.id)}
                                                </Table.Cell>
                                            )}
                                        </Table.Row>
                                    )}
                                </Table.Body>
                            </Table>
                        </div>
                    )}
                </div>

                {/* Pagination */}
                {totalPages > 1 && (
                    <div className="shrink-0 border-t border-secondary px-6 py-3">
                        <PaginationPageDefault
                            page={currentPage}
                            total={totalPages}
                            onPageChange={setCurrentPage}
                        />
                    </div>
                )}

                {/* Analysis slideout */}
                {(() => {
                    const call = slideoutCallId ? filtered.find(c => c.id === slideoutCallId) : null;
                    if (!call?.recording?.primaryLinkUrl) return null;
                    return (
                        <RecordingAnalysisSlideout
                            isOpen={true}
                            onOpenChange={(open) => { if (!open) setSlideoutCallId(null); }}
                            recordingUrl={call.recording.primaryLinkUrl}
                            callId={call.id}
                            agentName={call.agentName}
                            callerNumber={call.callerNumber?.primaryPhoneNumber ?? null}
                            direction={call.direction}
                            startedAt={call.startedAt}
                            durationSec={call.durationSec}
                            disposition={call.disposition}
                        />
                    );
                })()}
        </div>
    );
};
