'use client';

import { useEffect, useState } from 'react';
import { useMutation, useQuery } from 'convex/react';
import { Copy, RefreshCw, Trash2, Wrench } from 'lucide-react';
import { toast } from 'sonner';

import { api } from '@spoon/backend/convex/_generated/api.js';
import {
  AlertDialog,
  AlertDialogAction,
  AlertDialogCancel,
  AlertDialogContent,
  AlertDialogDescription,
  AlertDialogFooter,
  AlertDialogHeader,
  AlertDialogTitle,
  AlertDialogTrigger,
  Badge,
  Button,
  Card,
  CardContent,
  CardHeader,
  CardTitle,
  Input,
} from '@spoon/ui';

type WorkerHealth = {
  ok: boolean;
  workerId: string;
  convexUrl: string;
  runtime: string;
  containerRuntime: string;
  containerAccess: string;
  jobImage: string;
  workdir: string;
  network?: string;
  httpPort: number;
  activeWorkspaceCount: number;
  workspaceContainers: string[];
};

type CleanupResult = {
  removedContainers: string[];
  removedWorkdirs: string[];
};

export const WorkerHealthPanel = () => {
  const [health, setHealth] = useState<WorkerHealth | null>(null);
  const [healthError, setHealthError] = useState<string>();
  const [loadingHealth, setLoadingHealth] = useState(false);
  const [cleaning, setCleaning] = useState(false);
  const [deleting, setDeleting] = useState(false);
  const [olderThanDays, setOlderThanDays] = useState(7);
  const deletableCount =
    useQuery(api.agentJobs.countOldWorkspaces, { olderThanDays }) ?? 0;
  const deleteOldWorkspaces = useMutation(api.agentJobs.deleteOldWorkspaces);

  const copy = async (value: string) => {
    await navigator.clipboard.writeText(value);
    toast.success('Copied.');
  };

  const DiagnosticValue = ({ value }: { value: string }) => (
    <dd className='flex items-center gap-2 font-mono break-all'>
      <span>{value}</span>
      <Button
        type='button'
        variant='ghost'
        size='icon'
        onClick={() => void copy(value)}
      >
        <Copy className='size-3' />
      </Button>
    </dd>
  );

  const refreshHealth = async () => {
    setLoadingHealth(true);
    setHealthError(undefined);
    try {
      const response = await fetch('/api/agent-worker/health');
      if (!response.ok) throw new Error(await response.text());
      setHealth((await response.json()) as WorkerHealth);
    } catch (error) {
      const message = error instanceof Error ? error.message : String(error);
      setHealthError(message);
      setHealth(null);
    } finally {
      setLoadingHealth(false);
    }
  };

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

  const cleanupOrphans = async () => {
    setCleaning(true);
    try {
      const response = await fetch('/api/agent-worker/cleanup', {
        method: 'POST',
      });
      if (!response.ok) throw new Error(await response.text());
      const result = (await response.json()) as CleanupResult;
      toast.success(
        `Cleaned ${result.removedContainers.length} containers and ${result.removedWorkdirs.length} workdirs.`,
      );
      await refreshHealth();
    } catch (error) {
      console.error(error);
      toast.error('Could not clean worker resources.');
    } finally {
      setCleaning(false);
    }
  };

  const deleteOld = async () => {
    setDeleting(true);
    try {
      const result = await deleteOldWorkspaces({
        olderThanDays,
        limit: 100,
      });
      toast.success(`Deleted ${result.deleted} workspaces.`);
    } catch (error) {
      console.error(error);
      toast.error('Could not delete old workspaces.');
    } finally {
      setDeleting(false);
    }
  };

  return (
    <div className='space-y-4'>
      <Card className='shadow-none'>
        <CardHeader className='flex flex-row items-start justify-between gap-4'>
          <div>
            <CardTitle>Worker health</CardTitle>
            <p className='text-muted-foreground mt-1 text-sm'>
              Runtime status for the server-side agent worker.
            </p>
          </div>
          <Button
            type='button'
            variant='outline'
            size='sm'
            disabled={loadingHealth}
            onClick={() => void refreshHealth()}
          >
            <RefreshCw className='size-4' />
            Refresh
          </Button>
        </CardHeader>
        <CardContent className='space-y-4'>
          {healthError ? (
            <div className='border-destructive/40 bg-destructive/10 text-destructive rounded-md border p-3 text-sm'>
              {healthError}
            </div>
          ) : null}
          {health ? (
            <>
              <div className='flex flex-wrap gap-2'>
                <Badge variant={health.ok ? 'secondary' : 'destructive'}>
                  {health.ok ? 'healthy' : 'unhealthy'}
                </Badge>
                <Badge variant='outline'>{health.workerId}</Badge>
                <Badge variant='outline'>
                  {health.containerRuntime} / {health.containerAccess}
                </Badge>
              </div>
              <dl className='grid gap-3 text-sm md:grid-cols-2'>
                <div>
                  <dt className='text-muted-foreground'>Convex</dt>
                  <DiagnosticValue value={health.convexUrl} />
                </div>
                <div>
                  <dt className='text-muted-foreground'>Job image</dt>
                  <DiagnosticValue value={health.jobImage} />
                </div>
                <div>
                  <dt className='text-muted-foreground'>Workdir</dt>
                  <DiagnosticValue value={health.workdir} />
                </div>
                <div>
                  <dt className='text-muted-foreground'>Network</dt>
                  <dd className='font-mono break-all'>
                    {health.network ?? 'none'}
                  </dd>
                </div>
                <div>
                  <dt className='text-muted-foreground'>HTTP port</dt>
                  <dd>{health.httpPort}</dd>
                </div>
                <div>
                  <dt className='text-muted-foreground'>Active workspaces</dt>
                  <dd>{health.activeWorkspaceCount}</dd>
                </div>
              </dl>
              <div>
                <p className='text-muted-foreground text-sm'>
                  Workspace containers
                </p>
                <p className='mt-1 font-mono text-sm'>
                  {health.workspaceContainers.length
                    ? health.workspaceContainers.join(', ')
                    : 'none'}
                </p>
              </div>
            </>
          ) : !healthError ? (
            <p className='text-muted-foreground text-sm'>
              {loadingHealth ? 'Checking worker...' : 'No worker response yet.'}
            </p>
          ) : null}
        </CardContent>
      </Card>

      <Card className='shadow-none'>
        <CardHeader>
          <CardTitle>Cleanup</CardTitle>
          <p className='text-muted-foreground mt-1 text-sm'>
            Remove stopped workspace records and orphaned local worker
            resources.
          </p>
        </CardHeader>
        <CardContent className='space-y-4'>
          <div className='grid gap-3 md:grid-cols-[12rem_1fr_auto] md:items-end'>
            <label className='space-y-1'>
              <span className='text-sm font-medium'>Older than days</span>
              <Input
                type='number'
                min={0}
                value={olderThanDays}
                onChange={(event) =>
                  setOlderThanDays(
                    Math.max(Number.parseInt(event.target.value, 10) || 0, 0),
                  )
                }
              />
            </label>
            <p className='text-muted-foreground text-sm'>
              {deletableCount} stopped, cancelled, failed, timed out, or expired
              workspaces match this age filter.
            </p>
            <AlertDialog>
              <AlertDialogTrigger asChild>
                <Button
                  type='button'
                  variant='destructive'
                  disabled={deleting || deletableCount === 0}
                >
                  <Trash2 className='size-4' />
                  Delete old
                </Button>
              </AlertDialogTrigger>
              <AlertDialogContent>
                <AlertDialogHeader>
                  <AlertDialogTitle>
                    Delete old workspace records?
                  </AlertDialogTitle>
                  <AlertDialogDescription>
                    This deletes up to 100 stopped, cancelled, failed, timed
                    out, or expired workspaces older than {olderThanDays} days.
                    Active workspaces are not eligible.
                  </AlertDialogDescription>
                </AlertDialogHeader>
                <AlertDialogFooter>
                  <AlertDialogCancel>Keep records</AlertDialogCancel>
                  <AlertDialogAction
                    variant='destructive'
                    disabled={deleting}
                    onClick={() => void deleteOld()}
                  >
                    Delete old workspaces
                  </AlertDialogAction>
                </AlertDialogFooter>
              </AlertDialogContent>
            </AlertDialog>
          </div>

          <div className='border-border flex flex-col justify-between gap-3 rounded-md border p-3 md:flex-row md:items-center'>
            <div>
              <p className='text-sm font-medium'>Orphaned worker resources</p>
              <p className='text-muted-foreground text-sm'>
                Remove inactive Spoon job containers and inactive directories
                under the configured worker workdir.
              </p>
            </div>
            <Button
              type='button'
              variant='outline'
              disabled={cleaning}
              onClick={() => void cleanupOrphans()}
            >
              <Wrench className='size-4' />
              Clean orphans
            </Button>
          </div>
        </CardContent>
      </Card>
    </div>
  );
};
