import { useCallback, useEffect, useState } from 'react';
import type { ReactNode } from 'react';
import CloseIcon from '@mui/icons-material/Close';
import {
    Box,
    Button,
    Dialog,
    DialogActions,
    DialogContent,
    DialogTitle,
    IconButton,
    Table,
    TableBody,
    TableCell,
    TableContainer,
    TableHead,
    TableRow,
    Typography,
} from '@mui/material';
import api from '../services/api';
import D3WordCloud, {
    type WordCloudItem,
} from '../components/cloud/D3WordCloud';
import { useLocale } from '../context/LocaleContext';
import AppCard from '@/components/ui/Card';
import TypographyAnimated from '@/components/ui/TypographyAnimated';
import AppAudio from '@/components/ui/Audio';

/** Respuesta API: listas de `{ text, value }` (ver `WordCloudController::getWordCloud`). */
export type WordCloudResponse = {
    dataAgent: WordCloudApiPayload;
    dataContacto: WordCloudApiPayload;
};

type WordCloudApiPayload =
    | WordCloudItem[]
    | Record<string, number>
    | null
    | undefined;

function normalizeWordList(raw: WordCloudApiPayload): WordCloudItem[] {
    if (!raw) {
        return [];
    }
    if (Array.isArray(raw)) {
        return raw
            .map((row) => {
                if (
                    row &&
                    typeof row === 'object' &&
                    'text' in row &&
                    'value' in row
                ) {
                    const o = row as { text: unknown; value: unknown };
                    const text = String(o.text);
                    const value = Number(o.value);
                    if (!Number.isFinite(value)) {
                        return null;
                    }
                    return { text, value };
                }
                return null;
            })
            .filter((x): x is WordCloudItem => x !== null);
    }
    if (typeof raw === 'object') {
        return Object.entries(raw)
            .filter(
                ([, v]) => typeof v === 'number' && Number.isFinite(v as number),
            )
            .map(([text, value]) => ({ text, value: value as number }))
            .sort((a, b) => b.value - a.value);
    }
    return [];
}

const ENDPOINT =
    import.meta.env.VITE_WORDCLOUD_ENDPOINT ?? '/api/wordcloud';

const OCCURRENCES_ENDPOINT =
    import.meta.env.VITE_WORDCLOUD_OCCURRENCES_ENDPOINT ??
    '/api/wordcloud/occurrences';

/** Resaltado pastel celeste para la palabra buscada. */
const HIGHLIGHT_SKY = '#bfe8ff';

type WordOccurrenceChannel = 'Agente' | 'Contacto';

type WordOccurrenceRow = {
    transcription_id: number;
    cdr_id: number;
    agent_name: string;
    agent_surname: string;
    calldate: string;
    audio_route: string | null;
    start_time: number | null;
    transcript: string;
};

type OccurrencesApiResponse = {
    items: WordOccurrenceRow[];
    word: string;
    channel: WordOccurrenceChannel;
};

function resolveAudioSrc(audioRoute: string): string {
    const normalized = audioRoute.trim().replace(/^\/+/, '');
    if (/^https?:\/\//i.test(normalized)) {
        return normalized;
    }
    const base = import.meta.env.VITE_API_URL?.replace(/\/$/, '') ?? '';
    return `${base}/api/cdrs/audio/${normalized}`;
}

function formatCallDateDdMmYyyy(iso: string): string {
    const d = new Date(iso);
    if (Number.isNaN(d.getTime())) {
        return iso;
    }
    const pad = (n: number) => String(n).padStart(2, '0');
    return `${pad(d.getDate())}/${pad(d.getMonth() + 1)}/${d.getFullYear()}`;
}

/** `start_time` en segundos → `m:ss` o `mm:ss` (parte entera de segundos). */
function formatStartTimeMmSs(s: number | null | undefined): string {
    if (s == null || !Number.isFinite(Number(s))) {
        return '—';
    }
    const totalSec = Math.floor(Number(s));
    const m = Math.floor(totalSec / 60);
    const sec = totalSec % 60;
    return `${m}:${String(sec).padStart(2, '0')}`;
}

function isWordCharForHighlight(c: string): boolean {
    return /[0-9A-Za-záéíóúÁÉÍÓÚñÑ]/u.test(c);
}

function phraseWithWordHighlight(
    transcript: string,
    word: string,
): ReactNode {
    const w = word.trim().toLowerCase();
    if (!w || !transcript) {
        return transcript;
    }
    const lower = transcript.toLowerCase();
    const nodes: ReactNode[] = [];
    let i = 0;
    let markKey = 0;
    while (i < transcript.length) {
        const idx = lower.indexOf(w, i);
        if (idx === -1) {
            nodes.push(transcript.slice(i));
            break;
        }
        const beforeOk =
            idx === 0 || !isWordCharForHighlight(transcript[idx - 1]!);
        const endIdx = idx + w.length;
        const afterOk =
            endIdx >= transcript.length ||
            !isWordCharForHighlight(transcript[endIdx]!);
        const slice = transcript.slice(idx, endIdx);
        if (slice.toLowerCase() !== w || !beforeOk || !afterOk) {
            nodes.push(transcript.slice(i, idx + 1));
            i = idx + 1;
            continue;
        }
        if (idx > i) {
            nodes.push(transcript.slice(i, idx));
        }
        markKey += 1;
        nodes.push(
            <mark
                key={`mk-${idx}-${markKey}`}
                style={{
                    backgroundColor: HIGHLIGHT_SKY,
                    padding: '0 0.12em',
                    borderRadius: 3,
                }}
            >
                {slice}
            </mark>,
        );
        i = endIdx;
    }
    return <>{nodes}</>;
}

export default function Cloud() {
    const { t } = useLocale();

    const [itemsAgent, setItemsAgent] = useState<WordCloudItem[]>([]);
    const [itemsContacto, setItemsContacto] = useState<WordCloudItem[]>([]);

    const [totalDistinctAgent, setTotalDistinctAgent] = useState(0);
    const [totalDistinctContacto, setTotalDistinctContacto] = useState(0);

    const [loading, setLoading] = useState(true);
    const [error, setError] = useState<string | null>(null);

    const [pick, setPick] = useState<{
        word: string;
        channel: WordOccurrenceChannel;
    } | null>(null);
    const [occItems, setOccItems] = useState<WordOccurrenceRow[]>([]);
    const [occLoading, setOccLoading] = useState(false);
    const [occError, setOccError] = useState<string | null>(null);

    const load = useCallback(async () => {
        setLoading(true);
        setError(null);
        try {
            const { data } = await api.get<WordCloudResponse>(ENDPOINT);

            const agent = normalizeWordList(data.dataAgent);
            const contacto = normalizeWordList(data.dataContacto);
            setItemsAgent(agent);
            setTotalDistinctAgent(agent.length);
            setItemsContacto(contacto);
            setTotalDistinctContacto(contacto.length);
        } catch {
            setItemsAgent([]);
            setItemsContacto([]);
            setTotalDistinctAgent(0);
            setTotalDistinctContacto(0);
            setError(
                'No se pudo cargar la nube de palabras. Comprueba la API o tu sesión.',
            );
        } finally {
            setLoading(false);
        }
    }, []);

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

    useEffect(() => {
        if (!pick) {
            setOccItems([]);
            setOccError(null);
            setOccLoading(false);
            return;
        }
        setOccItems([]);
        let cancelled = false;
        (async () => {
            setOccLoading(true);
            setOccError(null);
            try {
                const { data } = await api.get<OccurrencesApiResponse>(
                    OCCURRENCES_ENDPOINT,
                    {
                        params: {
                            word: pick.word,
                            channel: pick.channel,
                        },
                    },
                );
                if (!cancelled) {
                    setOccItems(data.items ?? []);
                }
            } catch {
                if (!cancelled) {
                    setOccItems([]);
                    setOccError(t('cloud', 'occurrences_error'));
                }
            } finally {
                if (!cancelled) {
                    setOccLoading(false);
                }
            }
        })();
        return () => {
            cancelled = true;
        };
    }, [pick, t]);

    const handleWordAgent = useCallback((text: string) => {
        setPick({ word: text, channel: 'Agente' });
    }, []);

    const handleWordContact = useCallback((text: string) => {
        setPick({ word: text, channel: 'Contacto' });
    }, []);

    const closeOccurrences = useCallback(() => {
        setPick(null);
    }, []);

    return (
        <div className="container-fluid">
            <div className="row">
                <div className="col-12">
                    <AppCard>
                        <TypographyAnimated
                            variant="subtitle2"
                            prefix={t('cloud', 'top_heading_prefix')}
                            rotatingWords={t('cloud', 'top_heading_rotating')
                                .split('|')
                                .map((s) => s.trim())
                                .filter(Boolean)}
                            sx={{
                                color: 'text.primary',
                                fontWeight: 600,
                                textTransform: 'uppercase',
                                letterSpacing: '0.18em',
                                fontSize: '1.3rem',
                            }}
                        />
                        <div className="card-body mt-4">
                            {error ? (
                                <div className="alert alert-danger" role="alert">
                                    {error}
                                </div>
                            ) : null}
                            {loading ? (
                                <div
                                    className="d-flex align-items-center justify-content-center text-muted"
                                    style={{ width: '100%', height: 500 }}
                                >
                                    Cargando…
                                </div>
                            ) : itemsAgent.length === 0 &&
                              itemsContacto.length === 0 ? (
                                <div
                                    className="d-flex align-items-center justify-content-center text-muted"
                                    style={{ width: '100%', height: 500 }}
                                >
                                    {t('cloud', 'no_data_to_show')}
                                </div>
                            ) : (
                                <div
                                    className="align-items-stretch"
                                    style={{
                                        display: 'grid',
                                        width: '100%',
                                        gap: '1rem',
                                        gridTemplateColumns:
                                            'repeat(2, minmax(0, 1fr))',
                                    }}
                                >
                                    <div
                                        className="d-flex flex-column text-center"
                                        style={{ minWidth: 0 }}
                                    >
                                        <Typography
                                            variant="subtitle2"
                                            sx={{
                                                color: 'text.primary',
                                                fontWeight: 600,
                                                textTransform: 'uppercase',
                                                letterSpacing: '0.18em',
                                                fontSize: '0.82rem',
                                            }}
                                        >
                                            {t('cloud', 'agent')}
                                        </Typography>
                                        {itemsAgent.length === 0 ? (
                                            <div
                                                className="d-flex align-items-center justify-content-center text-muted border rounded flex-grow-1"
                                                style={{
                                                    width: '100%',
                                                    minHeight: 'min(50vh, 520px)',
                                                }}
                                            >
                                                Sin datos para este canal.
                                            </div>
                                        ) : (
                                            <div
                                                className="p-2 border rounded flex-grow-1 d-flex flex-column"
                                                style={{
                                                    width: '100%',
                                                    minHeight: 'min(50vh, 520px)',
                                                    border: '0px solid #dee2e6',
                                                }}
                                                aria-label={`Nube de palabras (Agente), ${totalDistinctAgent} términos distintos`}
                                            >
                                                <div
                                                    className="flex-grow-1"
                                                    style={{
                                                        minHeight: 0,
                                                        minWidth: 0,
                                                        height: 'min(50vh, 520px)',
                                                    }}
                                                >
                                                    <D3WordCloud
                                                        items={itemsAgent}
                                                        svgClassName="text-primary"
                                                        onWordClick={handleWordAgent}
                                                    />
                                                </div>
                                            </div>
                                        )}
                                    </div>
                                    <div
                                        className="d-flex flex-column text-center"
                                        style={{ minWidth: 0 }}
                                    >
                                        <Typography
                                            variant="subtitle2"
                                            sx={{
                                                color: 'text.primary',
                                                fontWeight: 600,
                                                textTransform: 'uppercase',
                                                letterSpacing: '0.18em',
                                                fontSize: '0.82rem',
                                            }}
                                        >
                                            {t('cloud', 'contact')}
                                        </Typography>
                                        {itemsContacto.length === 0 ? (
                                            <div
                                                className="d-flex align-items-center justify-content-center text-muted border rounded flex-grow-1"
                                                style={{
                                                    width: '100%',
                                                    minHeight: 'min(50vh, 520px)',
                                                }}
                                            >
                                                Sin datos para este canal.
                                            </div>
                                        ) : (
                                            <div
                                                className="p-2 border rounded flex-grow-1 d-flex flex-column"
                                                style={{
                                                    width: '100%',
                                                    minHeight: 'min(50vh, 520px)',
                                                    border: '0px solid #dee2e6',
                                                }}
                                                aria-label={`Nube de palabras (Contacto), ${totalDistinctContacto} términos distintos`}
                                            >
                                                <div
                                                    className="flex-grow-1"
                                                    style={{
                                                        minHeight: 0,
                                                        minWidth: 0,
                                                        height: 'min(50vh, 520px)',
                                                    }}
                                                >
                                                    <D3WordCloud
                                                        items={itemsContacto}
                                                        svgClassName="text-success"
                                                        onWordClick={handleWordContact}
                                                    />
                                                </div>
                                            </div>
                                        )}
                                    </div>
                                </div>
                            )}
                        </div>
                    </AppCard>

                    <Dialog
                        open={pick !== null}
                        onClose={closeOccurrences}
                        fullWidth
                        maxWidth={false}
                        scroll="paper"
                        PaperProps={{
                            sx: {
                                maxWidth: '90vw',
                                width: '90vw',
                                overflow: 'hidden',
                            },
                        }}
                    >
                        {pick ? (
                            <>
                                <DialogTitle
                                    sx={{
                                        display: 'flex',
                                        alignItems: 'center',
                                        justifyContent: 'space-between',
                                        gap: 1,
                                        pr: 1,
                                    }}
                                >
                                    <Typography component="span" variant="h6">
                                        {t('cloud', 'occurrences_title')
                                            .replace(':word', pick.word)
                                            .replace(
                                                ':channel',
                                                pick.channel === 'Agente'
                                                    ? t('cloud', 'agent')
                                                    : t('cloud', 'contact'),
                                            )}
                                    </Typography>
                                    <IconButton
                                        aria-label={t('cloud', 'close')}
                                        onClick={closeOccurrences}
                                        edge="end"
                                    >
                                        <CloseIcon />
                                    </IconButton>
                                </DialogTitle>
                                <DialogContent dividers >
                                    {occLoading ? (
                                        <Typography color="text.secondary">
                                            {t('cloud', 'occurrences_loading')}
                                        </Typography>
                                    ) : null}
                                    {occError ? (
                                        <Typography color="error" role="alert">
                                            {occError}
                                        </Typography>
                                    ) : null}
                                    {!occLoading &&
                                    !occError &&
                                    occItems.length === 0 ? (
                                        <Typography color="text.secondary">
                                            {t('cloud', 'occurrences_empty')}
                                        </Typography>
                                    ) : null}
                                    {!occLoading && occItems.length > 0 ? (
                                        <TableContainer
                                            component={Box}
                                            sx={{ maxHeight: 'min(70vh, 560px)' }}
                                        >
                                            <Table size="small" stickyHeader>
                                                <TableHead>
                                                    <TableRow>
                                                        <TableCell sx={{ width: '10%' }}>
                                                            {t(
                                                                'cloud',
                                                                'th_agent',
                                                            )}
                                                        </TableCell>
                                                        <TableCell sx={{ width: '5%' }}>
                                                            {t(
                                                                'cloud',
                                                                'th_date',
                                                            )}
                                                        </TableCell>
                                                        <TableCell sx={{ width: '20%' }}>
                                                            {t(
                                                                'cloud',
                                                                'th_audio',
                                                            )}
                                                        </TableCell>
                                                        <TableCell sx={{ width: '5%' }}>
                                                            {t(
                                                                'cloud',
                                                                'th_start_time',
                                                            )}
                                                        </TableCell>
                                                        <TableCell sx={{ width: '60%' }}>
                                                            {t(
                                                                'cloud',
                                                                'th_phrase',
                                                            )}
                                                        </TableCell>
                                                    </TableRow>
                                                </TableHead>
                                                <TableBody>
                                                    {occItems.map((row, rowIdx) => (
                                                        <TableRow
                                                            key={`${row.transcription_id}-${row.start_time ?? 't'}-${rowIdx}`}
                                                        >
                                                            <TableCell>
                                                                {[
                                                                    row.agent_name,
                                                                    row.agent_surname,
                                                                ]
                                                                    .map((s) =>
                                                                        s.trim(),
                                                                    )
                                                                    .filter(
                                                                        Boolean,
                                                                    )
                                                                    .join(' ') ||
                                                                    '—'}
                                                            </TableCell>
                                                            <TableCell>
                                                                {formatCallDateDdMmYyyy(
                                                                    row.calldate,
                                                                )}
                                                            </TableCell>
                                                            <TableCell
                                                                sx={{
                                                                    maxWidth: 280,
                                                                    verticalAlign:
                                                                        'middle',
                                                                }}
                                                            >
                                                                {row.audio_route ? (
                                                                    <AppAudio
                                                                        src={resolveAudioSrc(
                                                                            row.audio_route,
                                                                        )}
                                                                        fallbackText={t(
                                                                            'cloud',
                                                                            'no_audio',
                                                                        )}
                                                                    />
                                                                ) : (
                                                                    <Typography
                                                                        variant="body2"
                                                                        color="text.secondary"
                                                                    >
                                                                        {t(
                                                                            'cloud',
                                                                            'no_audio',
                                                                        )}
                                                                    </Typography>
                                                                )}
                                                            </TableCell>
                                                            <TableCell>
                                                                {formatStartTimeMmSs(
                                                                    row.start_time,
                                                                )}
                                                            </TableCell>
                                                            <TableCell
                                                                sx={{
                                                                    whiteSpace:
                                                                        'normal',
                                                                    wordBreak:
                                                                        'break-word',
                                                                }}
                                                            >
                                                                {phraseWithWordHighlight(
                                                                    row.transcript,
                                                                    pick.word,
                                                                )}
                                                            </TableCell>
                                                        </TableRow>
                                                    ))}
                                                </TableBody>
                                            </Table>
                                        </TableContainer>
                                    ) : null}
                                </DialogContent>
                                <DialogActions>
                                    <Button onClick={closeOccurrences}>
                                        {t('cloud', 'close')}
                                    </Button>
                                </DialogActions>
                            </>
                        ) : null}
                    </Dialog>
                </div>
            </div>
        </div>
    );
}
