'use client';
import { useState, useEffect } from 'react';
import { useQuery } from '@tanstack/react-query';
import { api } from '@/lib/api';
import { useAuth } from '@/lib/auth-context';
import { pushSupported, getPushStatus, enablePush, disablePush } from '@/lib/push';
import { IconTrash, IconCheck } from '@/components/ui';
import { DataTable, Pagination } from '@/components/data-table';
import { FloatInput, FloatArea } from '@/components/float';
import { DatePicker } from '@/components/date-picker';
import { useDialog } from '@/components/dialog';
import { formatDate, formatDateTime } from '@/lib/format';
import { validate, v, Errors } from '@/lib/validation';

const PAGE_SIZE = 10;

export default function Misc({ params }: { params?: any }) { return null; }

export function NotificationsPage() {
  const { notify } = useDialog();
  const [page, setPage] = useState(1);
  const [search, setSearch] = useState('');
  const q = useQuery({ queryKey: ['notif', page, search], queryFn: () => api.get(`/api/v1/notifications?search=${encodeURIComponent(search)}&page=${page}&limit=${PAGE_SIZE}`) });
  const [pushState, setPushState] = useState<'unknown' | 'on' | 'off' | 'unsupported' | 'unconfigured'>('unknown');
  useEffect(() => {
    if (!pushSupported()) { setPushState('unsupported'); return; }
    getPushStatus().then((s) => setPushState(s.pushEnabled ? (s.count > 0 ? 'on' : 'off') : 'unconfigured')).catch(() => {});
  }, []);
  return (
    <div className="space-y-2">
      <div className="card space-y-2">
        <h2 className="font-medium">Push notifications</h2>
        {pushState === 'unsupported' && <p className="text-sm text-slate-500">This browser does not support push notifications.</p>}
        {pushState === 'unconfigured' && <p className="text-sm text-slate-500">Push is not configured on the server yet.</p>}
        {(pushState === 'on' || pushState === 'off') && (
          <div className="flex gap-2 items-center">
            <span className="text-sm">{pushState === 'on' ? 'Enabled on this device — upcoming deviations, samples & escalations pop up in Chrome on login and in the background.' : 'Disabled on this device.'}</span>
            {pushState === 'on'
              ? <button className="btn-ghost text-sm" onClick={async () => { await disablePush(); setPushState('off'); }}>Disable</button>
              : <button className="btn-primary text-sm" onClick={async () => {
                  try { await enablePush(); setPushState('on'); notify('Push notifications enabled on this device.', { tone: 'success' }); }
                  catch (e: any) { notify(e.message, { tone: 'error' }); }
                }}>Enable push</button>}
          </div>
        )}
      </div>
      <div className="flex items-center"><h1 className="text-xl font-semibold mr-auto">Notifications ({q.data?.unread ?? 0} unread)</h1>
        <button className="btn-ghost text-sm" onClick={async () => { await api.post('/api/v1/notifications/read-all'); q.refetch(); }}>Mark all read</button></div>
      <DataTable
        caption="Notifications"
        rows={q.data?.data ?? []}
        keyOf={(n: any) => n.id}
        searchValue={search}
        onSearchChange={(v) => { setSearch(v); setPage(1); }}
        searchPlaceholder="Search notifications"
        empty={q.isLoading ? 'Loading…' : 'No notifications.'}
        columns={[
          { header: 'Title', render: (n: any) => <b>{n.title}</b> },
          { header: 'Message', render: (n: any) => <span className="text-slate-600">{n.message}</span> },
          { header: 'Received', render: (n: any) => <span className="whitespace-nowrap">{formatDateTime(n.created_at)}</span> },
          {
            header: 'Status', render: (n: any) => (n.is_read
              ? <span className="badge bg-slate-100">read</span>
              : <span className="badge bg-blue-600 text-white">new</span>),
          },
          {
            header: '', render: (n: any) => (!n.is_read
              ? <button type="button" aria-label="Mark as read" title="Mark read" className="btn-plain" onClick={async () => { await api.post(`/api/v1/notifications/${n.id}/read`); q.refetch(); }}><IconCheck /></button>
              : null),
          },
        ]}
      />
      <Pagination page={page} total={q.data?.total ?? 0} limit={PAGE_SIZE} onPage={setPage} />
    </div>
  );
}

function humanAction(action: string): string {
  return String(action ?? '').toLowerCase().split('_').map((w) => (w ? w[0].toUpperCase() + w.slice(1) : w)).join(' ');
}

function prettyDetails(l: any): string {
  const bits: string[] = [];
  if (l.record_id != null) bits.push(`Record: ${l.module} #${l.record_id}`);
  const show = (label: string, raw: any) => {
    if (raw == null || raw === '') return;
    let v: any = raw;
    try { v = typeof raw === 'string' ? JSON.parse(raw) : raw; } catch { /* keep raw */ }
    bits.push(`${label}: ${typeof v === 'object' ? JSON.stringify(v) : String(v)}`);
  };
  show('Was', l.old_value);
  show('Now', l.new_value);
  if (l.ip_address) bits.push(`IP: ${l.ip_address}`);
  return bits.join('\n');
}

export function AuditPage() {
  const [page, setPage] = useState(1);
  const [search, setSearch] = useState('');
  const [open, setOpen] = useState<number | null>(null);
  const q = useQuery({ queryKey: ['audit', page, search], queryFn: () => api.get(`/api/v1/audit-logs?search=${encodeURIComponent(search)}&page=${page}&limit=${PAGE_SIZE}`) });
  return (
    <div className="space-y-3">
      <h1 className="page-title">Audit Logs</h1>
      <DataTable
        caption="Audit logs"
        rows={q.data?.data ?? []}
        keyOf={(l: any) => l.id}
        searchValue={search}
        onSearchChange={(v) => { setSearch(v); setPage(1); }}
        searchPlaceholder="Search action / module / user"
        empty={q.isLoading ? 'Loading…' : 'No audit logs found.'}
        columns={[
          { header: 'When', render: (l: any) => <span className="whitespace-nowrap">{formatDateTime(l.created_at)}</span> },
          { header: 'User', render: (l: any) => <b>{l.user_name ?? 'System'}</b> },
          { header: 'Action', render: (l: any) => <span className="badge bg-slate-100 whitespace-nowrap">{humanAction(l.action)}</span> },
          {
            header: 'Record', render: (l: any) => (
              <button type="button" className="underline-offset-2 hover:underline text-left" title="Show details"
                onClick={() => setOpen(open === l.id ? null : l.id)} aria-expanded={open === l.id}>
                <span className="whitespace-nowrap">{l.record_id != null ? `${l.module} #${l.record_id}` : l.module}</span>
              </button>
            ),
          },
        ]}
      />
      {open != null && (() => {
        const row: any = (q.data?.data ?? []).find((l: any) => l.id === open);
        if (!row) return null;
        return (
          <div className="card" role="status">
            <p className="text-sm font-medium mb-1">
              {row.user_name ?? 'System'} · {humanAction(row.action)} · {row.record_id != null ? `${row.module} #${row.record_id}` : row.module}
            </p>
            <pre className="text-xs whitespace-pre-wrap font-mono rounded-lg p-3 overflow-x-auto" style={{ background: 'var(--bg)' }}>{prettyDetails(row) || 'No further details captured.'}</pre>
          </div>
        );
      })()}
      <Pagination page={page} total={q.data?.total ?? 0} limit={PAGE_SIZE} onPage={setPage} />
    </div>
  );
}

export function SettingsPage() {
  const { notify } = useDialog();
  const q = useQuery({ queryKey: ['settings'], queryFn: () => api.get('/api/v1/settings') });
  const [pw, setPw] = useState({ current: '', password: '', confirm: '' });
  const [pwErrs, setPwErrs] = useState<Errors>({});
  return (
    <div className="space-y-2">
      <h1 className="page-title">Settings</h1>
      <div className="card space-y-2">
        <h2 className="font-medium">Change password</h2>
        <FloatInput label="Current password" id="pw-current" type="password" autoComplete="current-password" error={pwErrs.current} value={pw.current} onChange={(e) => setPw({ ...pw, current: e.target.value })} />
        <div className="grid md:grid-cols-2 gap-2">
          <FloatInput label="New password (min 8)" id="pw-new" type="password" autoComplete="new-password" error={pwErrs.password} value={pw.password} onChange={(e) => setPw({ ...pw, password: e.target.value })} />
          <FloatInput label="Confirm new password" id="pw-confirm" type="password" autoComplete="new-password" error={pwErrs.confirm} value={pw.confirm} onChange={(e) => setPw({ ...pw, confirm: e.target.value })} />
        </div>
        <button className="btn-ghost text-sm btn-tall" onClick={async () => {
          const fe = validate({
            current: () => v.required(pw.current, 'Current password'),
            password: () => v.minLen(pw.password, 8, 'New password'),
            confirm: () => v.match(pw.password, pw.confirm, 'Passwords do not match'),
          });
          setPwErrs(fe);
          if (Object.keys(fe).length) return;
          try {
            await api.post('/api/v1/auth/change-password', pw);
            setPw({ current: '', password: '', confirm: '' });
            notify('Password changed.', { tone: 'success' });
          } catch (e: any) { notify(e.message, { tone: 'error' }); }
        }}>Change password</button>
      </div>
      <form className="card space-y-2" onSubmit={async (e) => {
        e.preventDefault();
        const fd = new FormData(e.target as HTMLFormElement);
        const vals = Object.fromEntries(fd.entries()) as Record<string, string>;
        const fe = validate({ org_name: () => v.minLen(vals.org_name ?? '', 2, 'Organization name') });
        if (fe.org_name) { notify(fe.org_name, { tone: 'error' }); return; }
        try {
          await api.put('/api/v1/settings', vals);
          notify('Settings saved.', { tone: 'success' });
        } catch (ex: any) { notify(ex.message, { tone: 'error' }); }
      }}>
        <FloatInput label="Organization name" id="set-org" name="org_name" defaultValue={q.data?.org_name ?? ''} />
        <FloatInput label="Timezone" id="set-tz" name="org_timezone" defaultValue={q.data?.org_timezone ?? 'Asia/Kolkata'} />
        <button className="btn-primary btn-tall">Save</button>
        <p className="text-xs text-slate-500">SMTP is configured via backend environment variables (never exposed to frontend).</p>
      </form>
      <TemplateEditor />
      <SlaEditor />
      <EscalationEditor />
      <HolidayManager />
      <RolePermissionsEditor />
    </div>
  );
}

const PERM_MODULES = [
  { v: 'deviation', label: 'Deviations' },
  { v: 'capa', label: 'CAPAs' },
  { v: 'sample', label: 'QC Samples' },
];
const PERM_ROLES = [
  { v: 'stakeholder', label: 'Stakeholder' },
  { v: 'employee', label: 'Employee' },
];
const PERM_ACTIONS = [
  { v: 'can_view', label: 'View' },
  { v: 'can_create', label: 'Create' },
  { v: 'can_update', label: 'Update' },
  { v: 'can_delete', label: 'Delete' },
];

/** Super-admin/admin checkbox matrix: what stakeholder & employee may do in this organisation. */
function RolePermissionsEditor() {
  const { user } = useAuth();
  const { notify } = useDialog();
  const isManager = user?.role === 'admin' || user?.role === 'super_admin';
  const q = useQuery({ queryKey: ['role-perms-manage'], queryFn: () => api.get('/api/v1/role-permissions'), enabled: isManager });
  const [vals, setVals] = useState<Record<string, boolean>>({});
  const [loaded, setLoaded] = useState(false);
  useEffect(() => {
    if (q.data && !loaded) {
      const m: Record<string, boolean> = {};
      for (const r of q.data as any[]) {
        for (const a of PERM_ACTIONS) m[`${r.role}.${r.module}.${a.v}`] = !!r[a.v];
      }
      setVals(m); setLoaded(true);
    }
  }, [q.data, loaded]);
  if (!isManager) return null;
  const get = (role: string, mod: string, act: string, fallback: boolean) => vals[`${role}.${mod}.${act}`] ?? fallback;
  const legacy = (role: string, act: string) => role === 'stakeholder' || act === 'can_view' || act === 'can_update';
  return (
    <div className="card space-y-2">
      <h2 className="font-medium">Role permissions</h2>
      <p className="text-xs text-slate-500">
        What stakeholders and employees may do with deviations, CAPAs and samples in this organisation
        {user?.role === 'super_admin' ? ' (uses your selected organisation context)' : ''}.
        Super admins and admins always have full access. Unchecked Update still allows employees their assigned status/progress flow only where explicitly permitted elsewhere.
      </p>
      <div className="table-wrap">
        <table className="table">
          <thead><tr>
            <th scope="col">Role</th><th scope="col">Module</th>
            {PERM_ACTIONS.map((a) => <th scope="col" key={a.v} className="text-center">{a.label}</th>)}
          </tr></thead>
          <tbody>
            {PERM_ROLES.map((r) => PERM_MODULES.map((m, mi) => (
              <tr key={`${r.v}-${m.v}`} className="border-t">
                {mi === 0 && <td rowSpan={PERM_MODULES.length} className="font-medium">{r.label}</td>}
                <td>{m.label}</td>
                {PERM_ACTIONS.map((a) => (
                  <td key={a.v} className="text-center">
                    <input type="checkbox" aria-label={`${r.label} ${m.label} ${a.label}`}
                      checked={get(r.v, m.v, a.v, legacy(r.v, a.v))}
                      onChange={(e) => setVals({ ...vals, [`${r.v}.${m.v}.${a.v}`]: e.target.checked })} />
                  </td>
                ))}
              </tr>
            )))}
          </tbody>
        </table>
      </div>
      <button className="btn-primary text-sm btn-tall" onClick={async () => {
        const permissions: any[] = [];
        for (const r of PERM_ROLES) for (const m of PERM_MODULES) {
          const row: any = { role: r.v, module: m.v };
          for (const a of PERM_ACTIONS) row[a.v] = get(r.v, m.v, a.v, legacy(r.v, a.v));
          permissions.push(row);
        }
        try {
          await api.put('/api/v1/role-permissions', { permissions });
          notify('Role permissions saved.', { tone: 'success' });
          setLoaded(false); q.refetch();
        } catch (e: any) { notify(e.message, { tone: 'error' }); }
      }}>Save permissions</button>
    </div>
  );
}

function EscalationEditor() {
  const { user } = useAuth();
  const { notify } = useDialog();
  const isAdmin = user?.role === 'admin' || user?.role === 'super_admin';
  const q = useQuery({ queryKey: ['escpol'], queryFn: () => api.get('/api/v1/escalation-policies'), enabled: isAdmin });
  const [vals, setVals] = useState<Record<string, { l2: string; l3: string }>>({});
  if (!isAdmin) return null;
  const list: any[] = q.data ?? [];
  const get = (p: any, k: 'l2' | 'l3') => vals[p.priority]?.[k] ?? String(k === 'l2' ? p.l2_hours : p.l3_hours);
  return (
    <div className="card space-y-2">
      <h2 className="font-medium">Escalation thresholds (hours overdue per priority)</h2>
      <p className="text-xs text-slate-500">L1 fires on the due date for all priorities. L2 notifies stakeholder + management, L3 pages management as critical. Saved per organisation (super-admin with no org selected edits globals).</p>
      <div className="table-wrap">
        <table className="table">
          <thead><tr>
            <th scope="col">Priority</th><th scope="col">L2 after (h)</th><th scope="col">L3 after (h)</th><th scope="col">Scope</th>
          </tr></thead>
          <tbody>
            {list.map((p: any) => (
              <tr key={p.priority}>
                <td className="font-medium">{p.priority}</td>
                <td><input type="number" min={0} max={8760} className="input text-sm max-w-28" value={get(p, 'l2')}
                  onChange={(e) => setVals({ ...vals, [p.priority]: { l2: e.target.value, l3: get(p, 'l3') } })} /></td>
                <td><input type="number" min={1} max={8760} className="input text-sm max-w-28" value={get(p, 'l3')}
                  onChange={(e) => setVals({ ...vals, [p.priority]: { l2: get(p, 'l2'), l3: e.target.value } })} /></td>
                <td className="text-xs text-slate-400">{p.scope}</td>
              </tr>
            ))}
          </tbody>
        </table>
      </div>
      <button className="btn-primary text-sm btn-tall" onClick={async () => {
        const policies = list.map((p: any) => ({
          priority: p.priority, l2_hours: Number(get(p, 'l2')), l3_hours: Number(get(p, 'l3')),
        }));
        const bad = policies.find((p) =>
          !Number.isInteger(p.l2_hours) || !Number.isInteger(p.l3_hours) ||
          p.l2_hours < 0 || p.l3_hours <= p.l2_hours || p.l3_hours > 8760);
        if (bad) { notify(`${bad.priority} needs whole hours with 0 ≤ L2 < L3 ≤ 8760.`, { tone: 'error' }); return; }
        try {
          await api.put('/api/v1/escalation-policies', { policies });
          notify('Thresholds saved.', { tone: 'success' }); setVals({}); q.refetch();
        } catch (e: any) { notify(e.message, { tone: 'error' }); }
      }}>Save thresholds</button>
    </div>
  );
}

function SlaEditor() {
  const { user } = useAuth();
  const { notify } = useDialog();
  const isAdmin = user?.role === 'admin' || user?.role === 'super_admin';
  const q = useQuery({ queryKey: ['sla'], queryFn: () => api.get('/api/v1/sla-policies'), enabled: isAdmin });
  const [days, setDays] = useState<Record<string, string>>({});
  if (!isAdmin) return null;
  const list: any[] = q.data ?? [];
  return (
    <div className="card space-y-2">
      <h2 className="font-medium">SLA targets (resolution days per priority)</h2>
      <p className="text-xs text-slate-500">A deviation breaches when open longer than its priority SLA or when escalated. Saved per organisation (super-admin with no org selected edits globals).</p>
      <div className="grid grid-cols-2 md:grid-cols-4 gap-2">
        {list.map((p: any) => (
          <div key={p.priority}>
            <label className="label">{p.priority} {p.scope !== 'builtin' && <span className="text-slate-400">({p.scope})</span>}</label>
            <input type="number" min={0} max={3650} className="input text-sm"
              value={days[p.priority] ?? String(p.days)}
              onChange={(e) => setDays({ ...days, [p.priority]: e.target.value })} />
          </div>
        ))}
      </div>
      <button className="btn-primary text-sm btn-tall" onClick={async () => {
        const policies = list.map((p: any) => ({ priority: p.priority, days: Number(days[p.priority] ?? p.days) }));
        const bad = policies.find((p) => !Number.isInteger(p.days) || p.days < 0 || p.days > 3650);
        if (bad) { notify(`${bad.priority} needs whole days 0–3650.`, { tone: 'error' }); return; }
        try {
          await api.put('/api/v1/sla-policies', { policies });
          notify('SLA targets saved.', { tone: 'success' }); setDays({}); q.refetch();
        } catch (e: any) { notify(e.message, { tone: 'error' }); }
      }}>Save SLA targets</button>
    </div>
  );
}

function HolidayManager() {
  const { user } = useAuth();
  const isAdmin = user?.role === 'admin' || user?.role === 'super_admin';
  const today = new Date().toISOString().slice(0, 10);
  const q = useQuery({ queryKey: ['holidays'], queryFn: () => api.get(`/api/v1/holidays?from=${today}&limit=200`) });
  const [date, setDate] = useState('');
  const [name, setName] = useState('');
  const [scope, setScope] = useState('org');
  const [holErr, setHolErr] = useState('');
  if (!isAdmin) return null;
  return (
    <div className="card space-y-2">
      <h2 className="font-medium">Holiday calendar</h2>
      <p className="text-xs text-slate-500">Reminders pause on weekends and these dates, resuming the next working day. Escalations still fire.</p>
      <div className="flex flex-wrap gap-2 items-start">
        <div className="w-44"><DatePicker label="Date" id="hol-date" error={holErr} value={date} onChange={setDate} /></div>
        <div className="w-64 max-w-full"><FloatInput label="Name" id="hol-name" error={holErr} value={name} onChange={(e) => setName(e.target.value)} /></div>
        {user?.role === 'super_admin' && (
          <select className="input h-14 text-sm min-w-44" aria-label="Holiday scope" title="Holiday scope" value={scope} onChange={(e) => setScope(e.target.value)}>
            <option value="org">This org</option><option value="global">Global</option>
          </select>
        )}
        <button className="btn-primary text-sm btn-tall" onClick={async () => {
          const fe = validate({ date: () => v.date(date, 'Date'), name: () => v.minLen(name, 2, 'Name') });
          const first = fe.date ?? fe.name;
          setHolErr(first ?? '');
          if (first) return;
          await api.post('/api/v1/holidays', { date, name: name.trim(), scope });
          setDate(''); setName(''); q.refetch();
        }}>Add</button>
      </div>
      {holErr && <p role="alert" className="field-error">{holErr}</p>}
      {(q.data?.data ?? []).map((h: any) => (
        <p key={h.id} className="text-sm border-t py-1 flex gap-2 items-center">
          <b className="text-xs whitespace-nowrap">{formatDate(h.date)}</b><span>{h.name}</span>
          <span className={`badge ${h.scope === 'global' ? 'bg-purple-100 text-purple-800' : 'bg-slate-100'}`}>{h.scope}</span>
          <button type="button" className="btn-plain ml-auto" aria-label={`Delete ${h.name}`} title="Delete" onClick={async () => {
            await api.del(`/api/v1/holidays/${h.id}`); q.refetch();
          }}><IconTrash /></button>
        </p>
      ))}
    </div>
  );
}

function TemplateEditor() {
  const { user } = useAuth();
  const { notify } = useDialog();
  const q = useQuery({ queryKey: ['templates'], queryFn: () => api.get('/api/v1/email-templates') });
  const [key, setKey] = useState('');
  const [subject, setSubject] = useState('');
  const [body, setBody] = useState('');
  const isAdmin = user?.role === 'admin';
  const open = (t: any) => { setKey(t.key); setSubject(t.subject); setBody(t.html_body); };
  return (
    <div className="card space-y-2">
      <h2 className="font-medium">Email Templates</h2>
      <p className="text-xs text-slate-500">Subjects/bodies support variables like {'{{user_name}}'}. {isAdmin ? 'Saving stores an override for your organisation (super-admin with no org selected edits the global default).' : 'Read-only (admin can edit).'}</p>
      <div className="grid gap-1">
        {(q.data ?? []).map((t: any) => (
          <button key={t.key} onClick={() => open(t)} className={`text-left text-sm border rounded-lg px-3 py-2 hover:bg-slate-50 ${key === t.key ? 'border-slate-900' : ''}`}>
            <b>{t.name}</b> <span className="text-slate-500 font-mono text-xs">{t.key}</span>
            <span className={`badge ml-2 ${t.scope === 'organisation' ? 'bg-blue-100 text-blue-800' : 'bg-slate-100'}`}>{t.scope === 'organisation' ? 'org override' : 'global'}</span>
            <span className="block text-xs text-slate-500">{t.subject}</span>
            {!!t.variables?.length && <span className="block text-xs text-slate-400">vars: {t.variables.map((v: string) => `{{${v}}}`).join(' ')}</span>}
          </button>
        ))}
      </div>
      {key && (
        <div className="space-y-2 border-t pt-2">
          <FloatInput label="Subject" id="tpl-subject" value={subject} onChange={(e) => setSubject(e.target.value)} disabled={!isAdmin} />
          <FloatArea label="HTML body" id="tpl-body" className="font-mono" rows={6} value={body} onChange={(e) => setBody(e.target.value)} disabled={!isAdmin} />
          {isAdmin && (
            <div className="flex gap-2">
              <button className="btn-primary text-sm btn-tall" onClick={async () => {
                try {
                  await api.put(`/api/v1/email-templates/${key}`, { subject, html_body: body });
                  notify('Template saved.', { tone: 'success' }); q.refetch();
                } catch (e: any) { notify(e.message, { tone: 'error' }); }
              }}>Save template</button>
              <button className="btn-ghost text-sm btn-tall" onClick={async () => {
                try {
                  await api.del(`/api/v1/email-templates/${key}`);
                  notify('Override removed — using global default.', { tone: 'success' }); q.refetch();
                } catch (e: any) { notify(e.message, { tone: 'error' }); }
              }}>Reset to global</button>
            </div>
          )}
        </div>
      )}
    </div>
  );
}
