'use client';

import { useEffect, useState } from 'react';

import {
  Accordion,
  AccordionContent,
  AccordionItem,
  AccordionTrigger,
} from '@/components/ui/accordion';
import { Button } from '@/components/ui/button';
import { Label } from '@/components/ui/label';
import { ScrollArea } from '@/components/ui/scroll-area';
import { apiFetch } from '@/lib/api/client';
import { formatEnum } from '@/lib/constants';
import { WarningCallout } from '@/components/ui/warning-callout';
import { cn } from '@/lib/utils';

/**
 * Three-state per-user permission editor.
 *
 * For every leaf in RolePermissions we render an Inherit / Grant / Deny
 * toggle. "Inherit" leaves the leaf out of the user_permission_overrides
 * map so the role + port-role-override baseline wins. "Grant" / "Deny"
 * write `true` / `false` and override the baseline.
 *
 * Baseline comes from the GET endpoint which already merges role + port-
 * role override + residential toggle, so the inherit-state label matches
 * what `withAuth` would resolve to today.
 */

const GROUP_LABELS: Record<string, string> = {
  clients: 'Clients',
  interests: 'Interests / Pipeline',
  berths: 'Berths',
  documents: 'Documents',
  expenses: 'Expenses',
  invoices: 'Invoices',
  payments: 'Payments',
  files: 'Files',
  email: 'Email',
  reminders: 'Reminders',
  calendar: 'Calendar',
  reports: 'Reports',
  document_templates: 'Document Templates',
  yachts: 'Yachts',
  companies: 'Companies',
  memberships: 'Company Memberships',
  tenancies: 'Tenancies',
  admin: 'Administration',
  residential_clients: 'Residential Clients',
  residential_interests: 'Residential Interests',
};

// Mirrors RolePermissions in src/lib/db/schema/users.ts - used as the
// canonical leaf list so the matrix shows every action even when the
// baseline JSON omits a key (older roles, partial overrides).
const PERMISSION_LEAVES: Record<string, string[]> = {
  clients: ['view', 'create', 'edit', 'delete', 'merge', 'export'],
  interests: [
    'view',
    'create',
    'edit',
    'delete',
    'change_stage',
    'override_stage',
    'generate_eoi',
    'export',
  ],
  berths: ['view', 'edit', 'import', 'manage_waiting_list', 'update_prices'],
  documents: [
    'view',
    'create',
    'edit',
    'send_for_signing',
    'upload_signed',
    'delete',
    'manage_folders',
  ],
  expenses: ['view', 'create', 'edit', 'delete', 'export', 'scan_receipt'],
  invoices: ['view', 'create', 'edit', 'delete', 'send', 'record_payment', 'export'],
  payments: ['view', 'record', 'delete'],
  files: ['view', 'upload', 'edit', 'delete', 'manage_folders'],
  email: ['view', 'send', 'configure_account'],
  reminders: ['view_own', 'view_all', 'create', 'edit_own', 'edit_all', 'assign_others'],
  calendar: ['connect', 'view_events'],
  reports: ['view_dashboard', 'view_analytics', 'export'],
  document_templates: ['view', 'generate', 'manage'],
  yachts: ['view', 'create', 'edit', 'delete', 'transfer'],
  companies: ['view', 'create', 'edit', 'delete'],
  memberships: ['view', 'manage'],
  tenancies: ['view', 'manage', 'cancel'],
  admin: [
    'manage_users',
    'view_audit_log',
    'manage_settings',
    'manage_webhooks',
    'manage_reports',
    'manage_custom_fields',
    'manage_forms',
    'manage_tags',
    'system_backup',
    'permanently_delete_clients',
  ],
  residential_clients: ['view', 'create', 'edit', 'delete'],
  residential_interests: ['view', 'create', 'edit', 'delete', 'change_stage'],
};

function formatAction(action: string): string {
  return formatEnum(action);
}

type Overrides = Record<string, Record<string, boolean>>;
type Baseline = Record<string, Record<string, boolean>> | null;

interface PermissionMatrixResponse {
  data: {
    baseline: Baseline;
    overrides: Overrides;
    isSuperAdmin: boolean;
  };
}

interface UserPermissionMatrixProps {
  userId: string;
}

export function UserPermissionMatrix({ userId }: UserPermissionMatrixProps) {
  const [baseline, setBaseline] = useState<Baseline>(null);
  const [overrides, setOverrides] = useState<Overrides>({});
  // Tracked so future revisions can surface a dirty-state indicator; the
  // ui-ux audit recommended one. Setter is wired now to capture the
  // server-canonical baseline post-save.
  const [, setOriginalOverrides] = useState<Overrides>({});
  const [isSuperAdmin, setIsSuperAdmin] = useState(false);
  const [loading, setLoading] = useState(true);
  const [saving, setSaving] = useState(false);
  const [message, setMessage] = useState<string | null>(null);

  useEffect(() => {
    let cancelled = false;
    void (async () => {
      setLoading(true);
      try {
        const res = await apiFetch<PermissionMatrixResponse>(
          `/api/v1/admin/users/${userId}/permission-overrides`,
        );
        if (cancelled) return;
        setBaseline(res.data.baseline);
        const fetched = res.data.overrides ?? {};
        setOverrides(fetched);
        setOriginalOverrides(fetched);
        setIsSuperAdmin(res.data.isSuperAdmin);
      } finally {
        if (!cancelled) setLoading(false);
      }
    })();
    return () => {
      cancelled = true;
    };
  }, [userId]);

  function getState(resource: string, action: string): 'inherit' | 'grant' | 'deny' {
    const v = overrides[resource]?.[action];
    if (v === true) return 'grant';
    if (v === false) return 'deny';
    return 'inherit';
  }

  function setState(resource: string, action: string, next: 'inherit' | 'grant' | 'deny') {
    setOverrides((prev) => {
      const copy: Overrides = { ...prev, [resource]: { ...(prev[resource] ?? {}) } };
      if (next === 'inherit') {
        delete copy[resource]![action];
        if (Object.keys(copy[resource]!).length === 0) delete copy[resource];
      } else {
        copy[resource]![action] = next === 'grant';
      }
      return copy;
    });
  }

  function baselineFor(resource: string, action: string): boolean {
    return baseline?.[resource]?.[action] === true;
  }

  async function save() {
    setSaving(true);
    setMessage(null);
    try {
      await apiFetch(`/api/v1/admin/users/${userId}/permission-overrides`, {
        method: 'PUT',
        body: { overrides },
      });
      setOriginalOverrides(overrides);
      setMessage('Overrides saved.');
    } catch (err: unknown) {
      setMessage(err instanceof Error ? err.message : 'Failed to save overrides');
    } finally {
      setSaving(false);
    }
  }

  if (loading) {
    return (
      <div className="py-6 text-center text-sm text-muted-foreground">Loading permissions…</div>
    );
  }

  if (isSuperAdmin) {
    return (
      <div className="rounded-md border bg-muted/30 p-4 text-sm text-muted-foreground">
        Super-admin users bypass per-port permission checks. Overrides don&apos;t apply here -
        revoke the super-admin flag on the Profile tab first.
      </div>
    );
  }

  if (!baseline) {
    return (
      <div className="rounded-md border bg-amber-50 p-4 text-sm text-amber-900">
        This user isn&apos;t assigned to this port, so the role baseline isn&apos;t resolvable.
        Assign them a role on the Profile tab before editing per-user permissions.
      </div>
    );
  }

  return (
    <div className="space-y-3">
      <WarningCallout icon={false}>
        <span className="text-xs">
          Permission overrides save <strong>on the button below</strong>, separately from the
          Profile &amp; role tab. Switching tabs or closing the drawer without clicking{' '}
          <strong>Save overrides</strong> drops your changes.
        </span>
      </WarningCallout>
      <p className="text-xs text-muted-foreground">
        Each toggle defaults to <strong>Inherit</strong> (role + port override decide). Switch to
        <strong> Grant</strong> or <strong>Deny</strong> to force the value for this user only.
      </p>

      <ScrollArea className="h-[420px] rounded-md border">
        <Accordion type="multiple" className="px-3">
          {Object.entries(PERMISSION_LEAVES).map(([resource, leaves]) => (
            <AccordionItem key={resource} value={resource}>
              <AccordionTrigger className="text-sm">
                {GROUP_LABELS[resource] ?? resource}
              </AccordionTrigger>
              <AccordionContent>
                <div className="space-y-2 pl-2 pb-2">
                  {leaves.map((action) => {
                    const state = getState(resource, action);
                    const inherited = baselineFor(resource, action);
                    return (
                      <div
                        key={action}
                        className="flex flex-wrap items-center justify-between gap-2 rounded-md border bg-background px-2 py-1.5"
                      >
                        <div className="text-sm">
                          <Label className="text-sm">{formatAction(action)}</Label>
                          <p className="text-xs text-muted-foreground">
                            Inherits: {inherited ? 'granted' : 'denied'}
                          </p>
                        </div>
                        <div
                          className="inline-flex rounded-md border bg-muted/30 p-0.5"
                          role="radiogroup"
                          aria-label={`${formatAction(action)} permission override`}
                        >
                          {(['inherit', 'grant', 'deny'] as const).map((opt) => (
                            <button
                              key={opt}
                              type="button"
                              role="radio"
                              aria-checked={state === opt}
                              onClick={() => setState(resource, action, opt)}
                              className={cn(
                                'rounded px-2 py-0.5 text-xs font-medium transition-colors',
                                state === opt
                                  ? opt === 'grant'
                                    ? 'bg-emerald-600 text-white'
                                    : opt === 'deny'
                                      ? 'bg-rose-600 text-white'
                                      : 'bg-foreground text-background'
                                  : 'text-muted-foreground hover:text-foreground',
                              )}
                            >
                              {opt[0]!.toUpperCase() + opt.slice(1)}
                            </button>
                          ))}
                        </div>
                      </div>
                    );
                  })}
                </div>
              </AccordionContent>
            </AccordionItem>
          ))}
        </Accordion>
      </ScrollArea>

      <div className="flex items-center gap-3">
        <Button size="sm" onClick={save} disabled={saving}>
          {saving ? 'Saving…' : 'Save overrides'}
        </Button>
        {message && <span className="text-xs text-muted-foreground">{message}</span>}
      </div>
    </div>
  );
}
