'use client';

import { useEffect, useState } from 'react';
import { useQuery } from '@tanstack/react-query';
import { formatDistanceToNow } from 'date-fns';

import { apiFetch } from '@/lib/api/client';
import { STAGE_LABELS, formatEnum, formatSource, type PipelineStage } from '@/lib/constants';

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

const ACTION_LABELS: Record<string, string> = {
  create: 'Created',
  update: 'Updated',
  delete: 'Deleted',
  archive: 'Archived',
  restore: 'Restored',
  merge: 'Merged',
  revert: 'Reverted',
};

function formatAction(action: string): string {
  return ACTION_LABELS[action] ?? action.charAt(0).toUpperCase() + action.slice(1);
}

function formatField(field: string | null): string | null {
  if (!field) return null;
  return field
    .replace(/_/g, ' ')
    .replace(/([a-z])([A-Z])/g, '$1 $2')
    .toLowerCase();
}

/** Resolve enum-typed values to their human-readable label so the row reads
 *  "10% Deposit" instead of "deposit_10pct". Returns the raw value for any
 *  unrecognised field/value. */
function formatValueForField(field: string | null, value: unknown): string {
  if (value === null || value === undefined) return '';
  if (field) {
    const f = field.replace(/_/g, '').toLowerCase();
    if (typeof value === 'string') {
      if (f === 'pipelinestage' || f === 'stage') {
        return STAGE_LABELS[value as PipelineStage] ?? formatEnum(value);
      }
      if (f === 'source') return formatSource(value) ?? value;
      if (f === 'leadcategory' || f === 'category' || f === 'outcome') {
        return formatEnum(value);
      }
    }
  }
  if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') {
    return String(value);
  }
  return JSON.stringify(value);
}

function summarize(row: AuditRow): string {
  const verb = formatAction(row.action);
  const field = formatField(row.fieldChanged);
  if (field) return `${verb} ${field}`;
  return verb;
}

interface Props {
  endpoint: string; // e.g. /api/v1/clients/{id}/activity
  emptyText?: string;
}

export function EntityActivityFeed({ endpoint, emptyText = 'No activity yet.' }: Props) {
  const [now, setNow] = useState(() => Date.now());

  // Re-render every minute so "x minutes ago" stays accurate without a
  // refetch.
  useEffect(() => {
    const t = setInterval(() => setNow(Date.now()), 60_000);
    return () => clearInterval(t);
  }, []);

  const { data, isLoading, error } = useQuery({
    queryKey: ['entity-activity', endpoint],
    queryFn: () => apiFetch<{ data: AuditRow[] }>(endpoint),
    staleTime: 30_000,
  });

  if (isLoading) {
    return <div className="text-sm text-muted-foreground py-6">Loading activity…</div>;
  }
  if (error) {
    return (
      <div className="text-sm text-red-600 py-6">
        Failed to load activity: {error instanceof Error ? error.message : 'unknown error'}
      </div>
    );
  }

  const rows = data?.data ?? [];
  if (rows.length === 0) {
    return <div className="text-sm text-muted-foreground py-6">{emptyText}</div>;
  }

  return (
    <ol className="relative border-l border-muted-foreground/20 ml-3 pl-6 space-y-4 py-2">
      {rows.map((row) => {
        const created = new Date(row.createdAt);
        const ago = formatDistanceToNow(created, { addSuffix: true });
        // touch `now` so the closure participates in the minute re-render
        void now;
        const actor = row.actor?.name || row.actor?.email || 'System';
        return (
          <li key={row.id} className="relative">
            <span className="absolute left-[-31px] top-1 h-2.5 w-2.5 rounded-full bg-primary/70 ring-2 ring-background" />
            <div className="text-sm">
              <span className="font-medium">{summarize(row)}</span>
              <span className="text-muted-foreground"> · {actor}</span>
            </div>
            <div className="text-xs text-muted-foreground" title={created.toISOString()}>
              {ago}
            </div>
            {row.fieldChanged && (row.oldValue !== null || row.newValue !== null) ? (
              <div className="mt-1 text-xs space-x-2">
                {row.oldValue !== null && row.oldValue !== undefined ? (
                  <span className="line-through text-muted-foreground">
                    {formatValueForField(row.fieldChanged, row.oldValue).slice(0, 80)}
                  </span>
                ) : null}
                {row.newValue !== null && row.newValue !== undefined ? (
                  <span className="text-foreground">
                    → {formatValueForField(row.fieldChanged, row.newValue).slice(0, 80)}
                  </span>
                ) : null}
              </div>
            ) : null}
          </li>
        );
      })}
    </ol>
  );
}
