'use client';

import { useEffect, useState, useCallback, useMemo } from 'react';
import { type ColumnDef } from '@tanstack/react-table';
import { formatDistanceToNow } from 'date-fns';
import { Search, X } from 'lucide-react';

import { DataTable } from '@/components/shared/data-table';
import { PageHeader } from '@/components/shared/page-header';
import { Badge } from '@/components/ui/badge';
import { Input } from '@/components/ui/input';
import { Button } from '@/components/ui/button';
import { Label } from '@/components/ui/label';
import {
  Select,
  SelectContent,
  SelectItem,
  SelectTrigger,
  SelectValue,
} from '@/components/ui/select';
import { apiFetch } from '@/lib/api/client';

interface AuditEntry {
  id: string;
  userId: string | null;
  action: string;
  entityType: string;
  entityId: string | null;
  fieldChanged: string | null;
  oldValue: Record<string, unknown> | null;
  newValue: Record<string, unknown> | null;
  metadata: Record<string, unknown> | null;
  ipAddress: string | null;
  createdAt: string;
  actor: { id: string; email: string; name: string } | null;
}

interface AuditResponse {
  data: AuditEntry[];
  pagination: { nextCursor: { createdAt: string; id: string } | null };
}

const ACTION_COLORS: Record<string, string> = {
  create: 'bg-green-600',
  update: 'bg-blue-500',
  delete: 'bg-red-600',
  archive: 'bg-orange-500',
  restore: 'bg-teal-500',
  login: 'bg-gray-500',
  permission_denied: 'bg-red-800',
  merge: 'bg-purple-500',
  revert: 'bg-amber-500',
};

const ENTITY_TYPES = [
  'client',
  'interest',
  'berth',
  'document',
  'expense',
  'invoice',
  'reminder',
  'user',
  'role',
  'port',
  'setting',
  'tag',
  'webhook',
];

function useDebounced<T>(value: T, ms = 300): T {
  const [v, setV] = useState(value);
  useEffect(() => {
    const t = setTimeout(() => setV(value), ms);
    return () => clearTimeout(t);
  }, [value, ms]);
  return v;
}

export function AuditLogList() {
  const [entries, setEntries] = useState<AuditEntry[]>([]);
  const [nextCursor, setNextCursor] = useState<{
    createdAt: string;
    id: string;
  } | null>(null);
  const [loading, setLoading] = useState(true);
  const [loadingMore, setLoadingMore] = useState(false);

  // Filter state — debounce text inputs.
  const [search, setSearch] = useState('');
  const [entityType, setEntityType] = useState<string>('all');
  const [action, setAction] = useState<string>('all');
  const [userId, setUserId] = useState('');
  const [dateFrom, setDateFrom] = useState('');
  const [dateTo, setDateTo] = useState('');

  const debouncedSearch = useDebounced(search);
  const debouncedUserId = useDebounced(userId);

  const queryString = useMemo(() => {
    const params = new URLSearchParams({ limit: '50' });
    if (entityType !== 'all') params.set('entityType', entityType);
    if (action !== 'all') params.set('action', action);
    if (debouncedSearch) params.set('search', debouncedSearch);
    if (debouncedUserId) params.set('userId', debouncedUserId);
    if (dateFrom) params.set('dateFrom', new Date(dateFrom).toISOString());
    if (dateTo) {
      const end = new Date(dateTo);
      end.setHours(23, 59, 59, 999);
      params.set('dateTo', end.toISOString());
    }
    return params.toString();
  }, [entityType, action, debouncedSearch, debouncedUserId, dateFrom, dateTo]);

  const fetchFirstPage = useCallback(async () => {
    setLoading(true);
    try {
      const res = await apiFetch<AuditResponse>(`/api/v1/admin/audit?${queryString}`);
      setEntries(res.data);
      setNextCursor(res.pagination.nextCursor);
    } finally {
      setLoading(false);
    }
  }, [queryString]);

  const loadMore = useCallback(async () => {
    if (!nextCursor) return;
    setLoadingMore(true);
    try {
      const params = new URLSearchParams(queryString);
      params.set('cursorAt', nextCursor.createdAt);
      params.set('cursorId', nextCursor.id);
      const res = await apiFetch<AuditResponse>(`/api/v1/admin/audit?${params}`);
      setEntries((prev) => [...prev, ...res.data]);
      setNextCursor(res.pagination.nextCursor);
    } finally {
      setLoadingMore(false);
    }
  }, [queryString, nextCursor]);

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

  function clearFilters() {
    setSearch('');
    setEntityType('all');
    setAction('all');
    setUserId('');
    setDateFrom('');
    setDateTo('');
  }

  const hasActiveFilter =
    Boolean(search) ||
    entityType !== 'all' ||
    action !== 'all' ||
    Boolean(userId) ||
    Boolean(dateFrom) ||
    Boolean(dateTo);

  const columns: ColumnDef<AuditEntry, unknown>[] = [
    {
      accessorKey: 'createdAt',
      header: 'Time',
      cell: ({ row }) => (
        <div className="text-sm">
          <div>{new Date(row.original.createdAt).toLocaleString()}</div>
          <div className="text-xs text-muted-foreground">
            {formatDistanceToNow(new Date(row.original.createdAt), { addSuffix: true })}
          </div>
        </div>
      ),
      size: 180,
    },
    {
      accessorKey: 'action',
      header: 'Action',
      cell: ({ row }) => (
        <Badge
          className={`${ACTION_COLORS[row.original.action] ?? 'bg-gray-500'} text-white text-xs`}
        >
          {row.original.action}
        </Badge>
      ),
      size: 110,
    },
    {
      accessorKey: 'entityType',
      header: 'Entity',
      cell: ({ row }) => (
        <div>
          <span className="font-medium capitalize">{row.original.entityType}</span>
          {row.original.entityId ? (
            <code className="ml-2 text-xs text-muted-foreground">
              {row.original.entityId.slice(0, 8)}…
            </code>
          ) : null}
        </div>
      ),
    },
    {
      id: 'changes',
      header: 'Changes',
      cell: ({ row }) => {
        const { newValue, fieldChanged } = row.original;
        if (fieldChanged) return <span className="text-sm">{fieldChanged}</span>;
        if (newValue) {
          const keys = Object.keys(newValue);
          return (
            <span className="text-xs text-muted-foreground">
              {keys.slice(0, 3).join(', ')}
              {keys.length > 3 ? ` +${keys.length - 3} more` : ''}
            </span>
          );
        }
        return <span className="text-xs text-muted-foreground">—</span>;
      },
    },
    {
      id: 'actor',
      header: 'Actor',
      cell: ({ row }) => {
        const { actor, userId: rawId } = row.original;
        if (actor) {
          return (
            <div className="text-sm">
              <div className="font-medium">{actor.name}</div>
              <div className="text-xs text-muted-foreground">{actor.email}</div>
            </div>
          );
        }
        if (rawId) {
          return <code className="text-xs">{rawId.slice(0, 8)}…</code>;
        }
        return <span className="text-xs text-muted-foreground">system</span>;
      },
      size: 200,
    },
  ];

  return (
    <div>
      <PageHeader
        title="Audit Log"
        eyebrow="Admin"
        description="Every state change in this port — fully searchable."
        variant="gradient"
      />

      <div className="mt-4 flex flex-wrap items-end gap-3">
        <div className="space-y-1.5">
          <Label htmlFor="audit-search" className="text-xs">
            Search
          </Label>
          <div className="relative w-72">
            <Search className="absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-muted-foreground" />
            <Input
              id="audit-search"
              className="pl-9"
              placeholder="entity id, action, vendor…"
              value={search}
              onChange={(e) => setSearch(e.target.value)}
              data-testid="audit-search"
            />
          </div>
        </div>

        <div className="space-y-1.5">
          <Label className="text-xs">Entity</Label>
          <Select value={entityType} onValueChange={setEntityType}>
            <SelectTrigger className="w-36" data-testid="audit-entity">
              <SelectValue />
            </SelectTrigger>
            <SelectContent>
              <SelectItem value="all">All entities</SelectItem>
              {ENTITY_TYPES.map((t) => (
                <SelectItem key={t} value={t}>
                  {t.charAt(0).toUpperCase() + t.slice(1)}
                </SelectItem>
              ))}
            </SelectContent>
          </Select>
        </div>

        <div className="space-y-1.5">
          <Label className="text-xs">Action</Label>
          <Select value={action} onValueChange={setAction}>
            <SelectTrigger className="w-36" data-testid="audit-action">
              <SelectValue />
            </SelectTrigger>
            <SelectContent>
              <SelectItem value="all">All actions</SelectItem>
              <SelectItem value="create">Create</SelectItem>
              <SelectItem value="update">Update</SelectItem>
              <SelectItem value="delete">Delete</SelectItem>
              <SelectItem value="archive">Archive</SelectItem>
              <SelectItem value="restore">Restore</SelectItem>
              <SelectItem value="merge">Merge</SelectItem>
              <SelectItem value="revert">Revert</SelectItem>
              <SelectItem value="login">Login</SelectItem>
              <SelectItem value="permission_denied">Permission denied</SelectItem>
            </SelectContent>
          </Select>
        </div>

        <div className="space-y-1.5">
          <Label htmlFor="audit-user" className="text-xs">
            User id
          </Label>
          <Input
            id="audit-user"
            className="w-44"
            placeholder="exact user id"
            value={userId}
            onChange={(e) => setUserId(e.target.value)}
          />
        </div>

        <div className="space-y-1.5">
          <Label htmlFor="audit-from" className="text-xs">
            From
          </Label>
          <Input
            id="audit-from"
            type="date"
            className="w-36"
            value={dateFrom}
            onChange={(e) => setDateFrom(e.target.value)}
          />
        </div>

        <div className="space-y-1.5">
          <Label htmlFor="audit-to" className="text-xs">
            To
          </Label>
          <Input
            id="audit-to"
            type="date"
            className="w-36"
            value={dateTo}
            onChange={(e) => setDateTo(e.target.value)}
          />
        </div>

        {hasActiveFilter ? (
          <Button variant="ghost" size="sm" onClick={clearFilters} className="ml-auto">
            <X className="mr-1.5 h-3 w-3" />
            Clear
          </Button>
        ) : null}
      </div>

      <div className="mt-4">
        <DataTable
          columns={columns}
          data={entries}
          isLoading={loading}
          getRowId={(row) => row.id}
          emptyState={
            <div className="text-center py-8">
              <p className="text-muted-foreground">No audit log entries found.</p>
            </div>
          }
        />
      </div>

      {nextCursor ? (
        <div className="mt-4 flex justify-center">
          <Button
            variant="outline"
            size="sm"
            disabled={loadingMore}
            onClick={() => void loadMore()}
            data-testid="audit-load-more"
          >
            {loadingMore ? 'Loading…' : 'Load more'}
          </Button>
        </div>
      ) : null}
    </div>
  );
}
