import React, { useEffect, useState } from 'react';
import { PageToolbar, SearchInput } from './shared/ui';
import axios from 'axios';
import { Button } from 'primereact/button';
import { Column } from 'primereact/column';
import { ConfirmDialog, confirmDialog } from 'primereact/confirmdialog';
import { DataTable } from 'primereact/datatable';
import { Dialog } from 'primereact/dialog';
import { Dropdown } from 'primereact/dropdown';
import { InputText } from 'primereact/inputtext';
import { Message } from 'primereact/message';
import { ProgressSpinner } from 'primereact/progressspinner';
import { Tag } from 'primereact/tag';

const STATUSES = [
    { label: 'Active', value: 1 },
    { label: 'Disabled', value: 0 },
];

const fmtDateTime = (v: string | null) => {
    if (!v) return '—';
    const d = new Date(v);
    return isNaN(d.getTime()) ? '—' : d.toLocaleString();
};

const ApiCredential = () => {
    const [items, setItems] = useState([]);
    const [search, setSearch] = useState('');
    const [is_loading, setIsLoading] = useState(true);
    const [is_responding, setIsResponding] = useState(false);
    const [dialog_visible, setDialogVisible] = useState(false);
    const [error_message, setErrorMessage] = useState<string | null>(null);
    const [item, setItem] = useState<any>({ id: null, name: null, status: 1 });

    /* ---- Token drawer state ---- */
    const [tokens_visible, setTokensVisible] = useState(false);
    const [tokens_target, setTokensTarget] = useState<any>(null);
    const [tokens, setTokens] = useState([]);
    const [tokens_loading, setTokensLoading] = useState(false);
    const [token_label, setTokenLabel] = useState('');

    /* ---- Show-once token state ---- */
    const [issued_token, setIssuedToken] = useState<string | null>(null);
    const [copied, setCopied] = useState(false);

    const list = async () => {
        setIsLoading(true);
        try {
            const response = await axios.get('/api_credential/list');
            setItems(response.data);
        } catch (error) {
            console.error('Failed to fetch API credentials:', error);
        } finally {
            setIsLoading(false);
        }
    };

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

    const firstError = (error: any): string => {
        const data = error?.response?.data;
        if (data?.errors) {
            const first: any = Object.values(data.errors)[0];
            return Array.isArray(first) ? first[0] : String(first);
        }
        return data?.message || 'Something went wrong. Try again.';
    };

    const add = () => {
        setErrorMessage(null);
        setItem({ id: null, name: null, status: 1 });
        setDialogVisible(true);
    };

    const edit = (row: any) => {
        setErrorMessage(null);
        setItem({ id: row.id, name: row.name, status: row.status });
        setDialogVisible(true);
    };

    const save = async () => {
        setIsResponding(true);
        setErrorMessage(null);
        try {
            if (item.id) {
                await axios.put('/api_credential/edit', { id: item.id, name: item.name, status: item.status });
            } else {
                await axios.post('/api_credential/add', { name: item.name, status: item.status });
            }
            list();
            setDialogVisible(false);
        } catch (error: any) {
            setErrorMessage(firstError(error));
        } finally {
            setIsResponding(false);
        }
    };

    const toggleStatus = (row: any) => {
        const turningOff = row.status === 1;
        confirmDialog({
            header: turningOff ? 'Disable credential' : 'Enable credential',
            message: turningOff
                ? `Disable ${row.name}? Its tokens stay on file but every API call will be refused until re-enabled.`
                : `Enable ${row.name}? Its existing tokens will start working again.`,
            icon: 'pi pi-exclamation-triangle',
            acceptLabel: turningOff ? 'Disable' : 'Enable',
            acceptClassName: turningOff ? 'p-button-danger' : '',
            accept: async () => {
                try {
                    await axios.post('/api_credential/toggle_status', { id: row.id });
                    list();
                } catch (error: any) {
                    alert(firstError(error));
                }
            },
        });
    };

    const openTokens = async (row: any) => {
        setTokensTarget(row);
        setTokensVisible(true);
        setIssuedToken(null);
        setTokenLabel('');
        setErrorMessage(null);
        await loadTokens(row.id);
    };

    const loadTokens = async (id: number) => {
        setTokensLoading(true);
        try {
            const response = await axios.get('/api_credential/tokens?id=' + id);
            setTokens(response.data);
        } catch (error) {
            console.error('Failed to fetch tokens:', error);
        } finally {
            setTokensLoading(false);
        }
    };

    const issueToken = async () => {
        setIsResponding(true);
        setErrorMessage(null);
        try {
            const response = await axios.post('/api_credential/token/issue', {
                id: tokens_target.id,
                label: token_label,
            });
            // This is the only time the plaintext exists — hold it in view until dismissed.
            setIssuedToken(response.data.token);
            setCopied(false);
            setTokenLabel('');
            await loadTokens(tokens_target.id);
            list();
        } catch (error: any) {
            setErrorMessage(firstError(error));
        } finally {
            setIsResponding(false);
        }
    };

    const copyToken = async () => {
        if (!issued_token) return;
        try {
            await navigator.clipboard.writeText(issued_token);
            setCopied(true);
            setTimeout(() => setCopied(false), 2000);
        } catch {
            setErrorMessage('Could not copy automatically — select the token and copy it manually.');
        }
    };

    const revokeToken = (token: any) => {
        confirmDialog({
            header: 'Revoke token',
            message: `Revoke "${token.name}"? Any integration using it will start getting 401s immediately. This cannot be undone.`,
            icon: 'pi pi-exclamation-triangle',
            acceptLabel: 'Revoke',
            acceptClassName: 'p-button-danger',
            accept: async () => {
                try {
                    await axios.delete('/api_credential/token/revoke', {
                        data: { id: tokens_target.id, token_id: token.id },
                    });
                    await loadTokens(tokens_target.id);
                    list();
                } catch (error: any) {
                    alert(firstError(error));
                }
            },
        });
    };

    const revokeAllTokens = () => {
        confirmDialog({
            header: 'Revoke all tokens',
            message: `Revoke every token for ${tokens_target?.name}? Use this if a token has leaked. This cannot be undone.`,
            icon: 'pi pi-exclamation-triangle',
            acceptLabel: 'Revoke all',
            acceptClassName: 'p-button-danger',
            accept: async () => {
                try {
                    await axios.delete('/api_credential/token/revoke_all', { data: { id: tokens_target.id } });
                    await loadTokens(tokens_target.id);
                    list();
                } catch (error: any) {
                    alert(firstError(error));
                }
            },
        });
    };

    const statusBodyTemplate = (row: any) =>
        <Tag value={row.status === 1 ? 'Active' : 'Disabled'} severity={row.status === 1 ? 'success' : 'danger'} />;

    const lastUsedBodyTemplate = (row: any) => <span>{fmtDateTime(row.last_used_at)}</span>;

    const manageBodyTemplate = (row: any) => (
        <div className="flex gap-2">
            <Button onClick={() => edit(row)} icon="pi pi-pencil" label="Edit" className="p-button-sm p-button-warning" />
            <Button onClick={() => openTokens(row)} icon="pi pi-key" label="Tokens" className="p-button-sm p-button-secondary" />
            <Button
                onClick={() => toggleStatus(row)}
                icon={row.status === 1 ? 'pi pi-ban' : 'pi pi-check'}
                label={row.status === 1 ? 'Disable' : 'Enable'}
                className={`p-button-sm ${row.status === 1 ? 'p-button-danger' : 'p-button-success'}`}
            />
        </div>
    );

    const tokenManageBodyTemplate = (row: any) => (
        <Button onClick={() => revokeToken(row)} icon="pi pi-trash" label="Revoke" className="p-button-sm p-button-danger" />
    );

    return (
        <div>
            <ConfirmDialog />
            <PageToolbar
                title="API Credentials"
                subtitle="Machine identities and Bearer tokens for the public API."
                filters={<SearchInput value={search} onChange={setSearch} placeholder="Search credentials…" />}
                actions={
                    <>
                        <Button icon="pi pi-refresh" onClick={list} className="p-button-text p-button-sm" />
                        <Button icon="pi pi-plus" label="Add" onClick={add} className="p-button-sm" />
                    </>
                }
            />
            <div className="my-3">
                {is_loading ? (<ProgressSpinner style={{ width: '2rem', height: '2rem' }} className="mr-3" />) : null}
                <DataTable value={items} tableStyle={{ minWidth: '50rem' }} paginator rows={10}
                    globalFilter={search} globalFilterFields={['name']}
                    emptyMessage="No API credentials yet.">
                    <Column field="name" header="Name" sortable />
                    <Column field="status" header="Status" body={statusBodyTemplate} sortable />
                    <Column field="token_count" header="Tokens" sortable />
                    <Column field="last_used_at" header="Last used" body={lastUsedBodyTemplate} sortable />
                    <Column header="Manage" body={manageBodyTemplate} />
                </DataTable>
            </div>

            <Dialog visible={dialog_visible} onHide={() => setDialogVisible(false)}
                header={item.id ? 'Edit API Credential' : 'Add API Credential'} modal className="p-fluid w-1/2">
                <div className="form-body">
                    <div className="form-group mb-3">
                        <label htmlFor="name">Name</label>
                        <InputText id="name" value={item.name || ''} placeholder="e.g. Mobile App"
                            onChange={(e) => setItem({ ...item, name: e.target.value })} />
                    </div>
                    <div className="form-group mb-3">
                        <label htmlFor="status">Status</label>
                        <Dropdown id="status" value={item.status} options={STATUSES}
                            onChange={(e) => setItem({ ...item, status: e.value })} placeholder="Status" />
                    </div>
                    <div className="flex gap-2 mt-4 align-items-center">
                        {is_responding ? (<ProgressSpinner style={{ width: '2rem', height: '2rem' }} className="mr-3" />) : null}
                        {error_message ? (<Message severity="error" text={error_message} />) : null}
                        <Button raised label="Save" onClick={save} disabled={is_responding} />
                    </div>
                </div>
            </Dialog>

            <Dialog visible={tokens_visible} onHide={() => setTokensVisible(false)}
                header={`Tokens — ${tokens_target?.name ?? ''}`} modal className="p-fluid" style={{ width: '46rem' }}>
                <div className="form-body">
                    {issued_token && (
                        <div className="mb-4">
                            <Message severity="warn" className="mb-2"
                                text="Copy this token now — it is shown once and cannot be retrieved again." />
                            <div className="flex gap-2 align-items-center mt-2">
                                <InputText value={issued_token} readOnly
                                    onFocus={(e) => e.target.select()}
                                    style={{ fontFamily: 'JetBrains Mono, monospace', fontSize: '0.8rem' }} />
                                <Button icon={copied ? 'pi pi-check' : 'pi pi-copy'} label={copied ? 'Copied' : 'Copy'}
                                    onClick={copyToken} className="p-button-sm" style={{ width: 'auto' }} />
                            </div>
                        </div>
                    )}

                    <div className="flex gap-2 align-items-end mb-4">
                        <div className="flex-1">
                            <label htmlFor="token_label">New token label</label>
                            <InputText id="token_label" value={token_label} placeholder="e.g. production-server"
                                onChange={(e) => setTokenLabel(e.target.value)} />
                        </div>
                        <Button label="Issue token" icon="pi pi-plus" onClick={issueToken}
                            disabled={is_responding || !token_label.trim()} className="p-button-sm" style={{ width: 'auto' }} />
                    </div>

                    {error_message ? (<Message severity="error" text={error_message} className="mb-3" />) : null}

                    {tokens_loading ? (<ProgressSpinner style={{ width: '2rem', height: '2rem' }} />) : null}
                    <DataTable value={tokens} emptyMessage="No tokens issued yet." tableStyle={{ minWidth: '30rem' }}>
                        <Column field="name" header="Label" />
                        <Column header="Created" body={(r: any) => fmtDateTime(r.created_at)} />
                        <Column header="Last used" body={(r: any) => fmtDateTime(r.last_used_at)} />
                        <Column header="" body={tokenManageBodyTemplate} />
                    </DataTable>

                    {tokens.length > 0 && (
                        <div className="flex justify-content-end mt-3">
                            <Button label="Revoke all" icon="pi pi-trash" onClick={revokeAllTokens}
                                className="p-button-sm p-button-outlined p-button-danger" style={{ width: 'auto' }} />
                        </div>
                    )}
                </div>
            </Dialog>
        </div>
    );
};

export default ApiCredential;
