import { useState } from 'react';
import { Server, Wrench, Loader2, RefreshCw, Trash2 } from 'lucide-react';
import { toast } from 'sonner';
import { useGlobal } from 'hooks/useGlobal';
import { usePanelChannel } from 'hooks/usePanelChannel';
import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import {
  AlertDialog,
  AlertDialogAction,
  AlertDialogCancel,
  AlertDialogContent,
  AlertDialogDescription,
  AlertDialogFooter,
  AlertDialogHeader,
  AlertDialogTitle,
} from '@/components/ui/alert-dialog';
import { useResources, getResourceCategory, type Resource, type PingResult } from '@/state/useResources';
import { RUN_COMMAND_CHANNEL, type RunCommandState } from './run-command-channel';

type ConnectionSectionProps = {
  resource: Resource;
};

const ConnectionSection = ({ resource }: ConnectionSectionProps) => {
  const { saveConnectionConfig, pingResource } = useResources();
  const [url, setUrl] = useState(resource.connectionConfig?.url ?? '');
  const [apiKey, setApiKey] = useState(resource.connectionConfig?.credentials?.apiKey ?? '');
  const [username, setUsername] = useState(resource.connectionConfig?.credentials?.username ?? '');
  const [password, setPassword] = useState(resource.connectionConfig?.credentials?.password ?? '');
  const [pinging, setPinging] = useState(false);
  const [pingResult, setPingResult] = useState<PingResult | null>(null);
  const [saving, setSaving] = useState(false);

  const handlePing = async () => {
    setPinging(true);
    setPingResult(null);
    try {
      const result = await pingResource(resource.id, url);
      setPingResult(result);
    } catch {
      setPingResult({ reachable: false, latencyMs: null });
    } finally {
      setPinging(false);
    }
  };

  const handleSave = async () => {
    setSaving(true);
    try {
      const credentials =
        apiKey || username || password
          ? { apiKey: apiKey || undefined, username: username || undefined, password: password || undefined }
          : undefined;
      await saveConnectionConfig(resource.id, { url, credentials });
    } finally {
      setSaving(false);
    }
  };

  const hasCredentials = !!(
    resource.connectionConfig?.credentials?.apiKey || resource.connectionConfig?.credentials?.username
  );

  return (
    <div className="mb-6">
      <h3 className="text-sm font-semibold text-duck-dark mb-3">Connection</h3>
      <div className="flex flex-col gap-3">
        <div>
          <label className="text-xs text-duck-dark/50 mb-1 block">Base URL</label>
          <Input
            value={url}
            onChange={(ev) => setUrl(ev.target.value)}
            placeholder="http://127.0.0.1:64202"
            className="h-8 text-xs"
          />
        </div>
        {(hasCredentials || apiKey) && (
          <div>
            <label className="text-xs text-duck-dark/50 mb-1 block">API Key</label>
            <Input
              value={apiKey}
              onChange={(ev) => setApiKey(ev.target.value)}
              placeholder="Optional"
              type="password"
              className="h-8 text-xs"
            />
          </div>
        )}
        {(hasCredentials || username || password) && (
          <div className="flex gap-2">
            <div className="flex-1">
              <label className="text-xs text-duck-dark/50 mb-1 block">Username</label>
              <Input
                value={username}
                onChange={(ev) => setUsername(ev.target.value)}
                placeholder="Optional"
                className="h-8 text-xs"
              />
            </div>
            <div className="flex-1">
              <label className="text-xs text-duck-dark/50 mb-1 block">Password</label>
              <Input
                value={password}
                onChange={(ev) => setPassword(ev.target.value)}
                placeholder="Optional"
                type="password"
                className="h-8 text-xs"
              />
            </div>
          </div>
        )}
        <div className="flex items-center gap-2">
          <Button variant="outline" size="sm" onClick={handlePing} disabled={pinging || !url} className="text-xs">
            {pinging && <Loader2 className="h-3 w-3 animate-spin mr-1" />}
            Test Connection
          </Button>
          <Button size="sm" onClick={handleSave} disabled={saving || !url} className="text-xs">
            {saving && <Loader2 className="h-3 w-3 animate-spin mr-1" />}
            Save
          </Button>
          {pingResult && (
            <span className={`text-xs ${pingResult.reachable ? 'text-green-600' : 'text-red-500'}`}>
              {pingResult.reachable ? `Reachable (${pingResult.latencyMs}ms)` : 'Unreachable'}
            </span>
          )}
        </div>
      </div>
    </div>
  );
};

type LocalAvailabilitySectionProps = {
  resource: Resource;
  onRun: (command: string) => void;
};

type ResourceAction = 'install' | 'uninstall' | 'verify' | 'update' | 'manage';

const LocalAvailabilitySection = ({ resource, onRun }: LocalAvailabilitySectionProps) => {
  const { runCommand } = useResources();
  const [runningAction, setRunningAction] = useState<ResourceAction | null>(null);

  const isSudo = (cmd: string) => cmd.trimStart().startsWith('sudo');

  const handleAction = async (action: ResourceAction, command: string) => {
    if (isSudo(command)) {
      onRun(command);
      return;
    }
    setRunningAction(action);
    try {
      const result = await runCommand(resource.id, action);
      if (result.exitCode === 0) {
        toast.success('Command completed successfully');
      } else {
        toast.error(result.output || `Command failed (exit code ${result.exitCode})`, { duration: 8000 });
      }
    } catch {
      toast.error('Failed to run command');
    } finally {
      setRunningAction(null);
    }
  };

  return (
    <div className="flex flex-col gap-2">
      {resource.installed ? (
        <>
          <div>
            <span className="text-xs bg-green-100 text-green-700 rounded-full px-2 py-0.5">Installed</span>
          </div>
          {resource.version && (
            <div className="flex items-center gap-2">
              {resource.updateCommand && (
                <Button
                  variant="outline"
                  size="sm"
                  className="h-6 text-xs cursor-pointer"
                  onClick={() => handleAction('update', resource.updateCommand!)}
                  disabled={!!runningAction}
                >
                  <RefreshCw className={`h-3 w-3 mr-1 ${runningAction === 'update' ? 'animate-spin' : ''}`} />
                  Update
                </Button>
              )}
              <span className="text-xs text-duck-dark/50 dark:text-foreground/50">{resource.version}</span>
            </div>
          )}
          <div className="flex items-center gap-1.5">
            {!resource.version && resource.updateCommand && (
              <Button
                variant="outline"
                size="sm"
                className="h-6 text-xs cursor-pointer"
                onClick={() => handleAction('update', resource.updateCommand!)}
                disabled={!!runningAction}
              >
                <RefreshCw className={`h-3 w-3 mr-1 ${runningAction === 'update' ? 'animate-spin' : ''}`} />
                Update
              </Button>
            )}
            {resource.verifyCommand && (
              <Button
                variant="outline"
                size="sm"
                className="h-6 text-xs cursor-pointer"
                onClick={() => handleAction('verify', resource.verifyCommand!)}
                disabled={!!runningAction}
              >
                {runningAction === 'verify' && <Loader2 className="h-3 w-3 mr-1 animate-spin" />}
                Verify
              </Button>
            )}
            {resource.manageCommand && (
              <Button
                variant="outline"
                size="sm"
                className="h-6 text-xs cursor-pointer"
                onClick={() => handleAction('manage', resource.manageCommand!)}
                disabled={!!runningAction}
              >
                {runningAction === 'manage' && <Loader2 className="h-3 w-3 mr-1 animate-spin" />}
                Manage
              </Button>
            )}
          </div>
          {resource.uninstallCommand && (
            <div className="flex items-center mt-1.5">
              <Button
                variant="outline"
                size="sm"
                className="h-6 text-xs cursor-pointer text-red-500 hover:text-red-600 border-red-500/30 hover:border-red-500/50 hover:bg-red-500/5"
                onClick={() => handleAction('uninstall', resource.uninstallCommand!)}
                disabled={!!runningAction}
              >
                {runningAction === 'uninstall' ? (
                  <Loader2 className="h-3 w-3 mr-1 animate-spin" />
                ) : (
                  <Trash2 className="h-3 w-3 mr-1" />
                )}
                Uninstall
              </Button>
            </div>
          )}
        </>
      ) : (
        <div className="flex items-center gap-3">
          <span className="text-xs bg-duck-dark/5 text-duck-dark/40 rounded-full px-2 py-0.5">Not installed</span>
          {resource.installCommand && (
            <Button
              size="sm"
              className="h-6 text-xs bg-duck-teal text-duck-yellow hover:bg-duck-teal/90 cursor-pointer"
              onClick={() => handleAction('install', resource.installCommand!)}
              disabled={runningAction === 'install'}
            >
              {runningAction === 'install' ? 'Installing...' : 'Install'}
            </Button>
          )}
        </div>
      )}
    </div>
  );
};

type CatalogCardProps = {
  resource: Resource;
  onSelect: (id: string) => void;
};

const CatalogCard = ({ resource: r, onSelect }: CatalogCardProps) => {
  const category = getResourceCategory(r);
  return (
    <button
      onClick={() => onSelect(r.id)}
      className="flex flex-col gap-2 p-4 rounded-lg border border-duck-dark/10 text-left cursor-pointer transition-colors hover:border-duck-teal/30 hover:bg-duck-teal/5"
    >
      <div className="flex items-center gap-2">
        {r.port ? (
          <Server className="h-3.5 w-3.5 text-duck-teal shrink-0" />
        ) : (
          <Wrench className="h-3.5 w-3.5 text-duck-dark/40 shrink-0" />
        )}
        <span className="text-sm font-medium text-duck-dark truncate">{r.name}</span>
      </div>
      <p className="text-xs text-duck-dark/40 line-clamp-1">{r.subtitle}</p>
      <div className="flex items-center gap-1.5">
        <span className="text-[10px] bg-duck-dark/5 text-duck-dark/40 rounded-full px-1.5 py-0.5">{r.type}</span>
        <span
          className={`text-[10px] rounded-full px-1.5 py-0.5 ${category === 'api-based' ? 'bg-duck-teal/10 text-duck-teal' : 'bg-duck-dark/5 text-duck-dark/40'}`}
        >
          {category === 'api-based' ? 'API' : 'CLI'}
        </span>
      </div>
    </button>
  );
};

const ResourceCatalog = () => {
  const { resources, isLoading } = useResources();
  const [, setSelectedId] = useGlobal<string | null>('RESOURCE_SELECTED', null);
  const [, setShowCatalog] = useGlobal<boolean>('RESOURCE_CATALOG', false);
  const [search, setSearch] = useState('');

  const query = search.toLowerCase();
  const filtered =
    resources?.filter(
      (r: Resource) =>
        !r.installed &&
        (r.name.toLowerCase().includes(query) ||
          r.subtitle.toLowerCase().includes(query) ||
          r.description.toLowerCase().includes(query)),
    ) ?? [];

  const apiBased = filtered.filter((r: Resource) => getResourceCategory(r) === 'api-based');
  const localCli = filtered.filter((r: Resource) => getResourceCategory(r) === 'local-cli');

  const handleSelect = (id: string) => {
    setShowCatalog(false);
    setSelectedId(id);
  };

  return (
    <div className="h-full overflow-y-auto p-6">
      <h2 className="text-lg font-bold text-duck-dark mb-1">Resource Catalog</h2>
      <p className="text-sm text-duck-dark/40 mb-4">All available resources. Select one to configure.</p>
      <Input
        placeholder="Search resources..."
        value={search}
        onChange={(ev) => setSearch(ev.target.value)}
        className="h-8 text-xs mb-4 max-w-xs"
      />
      {isLoading && <p className="text-xs text-duck-dark/50">Loading...</p>}
      {apiBased.length > 0 && (
        <div className="mb-6">
          <div className="flex items-center gap-2 mb-3">
            <Server className="h-3.5 w-3.5 text-duck-teal" />
            <span className="text-xs font-semibold uppercase tracking-wider text-duck-dark/40">API Based</span>
          </div>
          <div className="grid grid-cols-2 xl:grid-cols-3 gap-3">
            {apiBased.map((r: Resource) => (
              <CatalogCard key={r.id} resource={r} onSelect={handleSelect} />
            ))}
          </div>
        </div>
      )}
      {localCli.length > 0 && (
        <div>
          <div className="flex items-center gap-2 mb-3">
            <Wrench className="h-3.5 w-3.5 text-duck-dark/40" />
            <span className="text-xs font-semibold uppercase tracking-wider text-duck-dark/40">Local CLI</span>
          </div>
          <div className="grid grid-cols-2 xl:grid-cols-3 gap-3">
            {localCli.map((r: Resource) => (
              <CatalogCard key={r.id} resource={r} onSelect={handleSelect} />
            ))}
          </div>
        </div>
      )}
    </div>
  );
};

const ResourceDetail = ({ resource }: { resource: Resource }) => {
  const category = getResourceCategory(resource);
  const [, setRunCommand] = usePanelChannel<RunCommandState>(RUN_COMMAND_CHANNEL, null);
  const [confirmCommand, setConfirmCommand] = useState<string | null>(null);

  const handleRun = (command: string) => {
    const isSudo = command.trimStart().startsWith('sudo');
    if (isSudo) {
      setConfirmCommand(command);
    } else {
      setRunCommand({ command });
    }
  };

  return (
    <>
      <div className="h-full overflow-y-auto p-6">
        <div className="flex items-center gap-2 mb-1">
          {resource.port ? (
            <Server className="h-4 w-4 text-duck-teal shrink-0" />
          ) : (
            <Wrench className="h-4 w-4 text-duck-dark/40 shrink-0" />
          )}
          <h2 className="text-lg font-bold text-duck-dark">{resource.name}</h2>
          <span className="text-sm text-duck-dark/40">{resource.subtitle}</span>
        </div>

        <div className="flex items-center gap-2 mb-4">
          <span className="text-xs bg-duck-dark/5 text-duck-dark/50 rounded-full px-2 py-0.5">{resource.type}</span>
          <span
            className={`text-xs rounded-full px-2 py-0.5 ${category === 'api-based' ? 'bg-duck-teal/10 text-duck-teal' : 'bg-duck-dark/5 text-duck-dark/50'}`}
          >
            {category === 'api-based' ? 'API Based' : 'Local CLI'}
          </span>
          {resource.port && (
            <span className="text-xs bg-duck-teal/10 text-duck-teal rounded-full px-2 py-0.5">:{resource.port}</span>
          )}
        </div>

        <p className="text-sm text-duck-dark/70 mb-6">{resource.description}</p>

        {category === 'api-based' && <ConnectionSection key={resource.id} resource={resource} />}
        <LocalAvailabilitySection resource={resource} onRun={handleRun} />
      </div>

      <AlertDialog open={!!confirmCommand} onOpenChange={(open) => !open && setConfirmCommand(null)}>
        <AlertDialogContent>
          <AlertDialogHeader>
            <AlertDialogTitle>Run with elevated privileges</AlertDialogTitle>
          </AlertDialogHeader>
          <p className="text-sm text-duck-dark/70 dark:text-foreground/70">
            For this operation the script must be run with elevated privileges (sudo) on the host machine.
            <br />
            Not to worry, though, we wrote it and battle tested it ourselves.
          </p>
          <code className="text-sm font-mono bg-[#1a1a2e] text-[#e0e0e0] rounded-lg px-3 py-2 break-all">{confirmCommand}</code>
          <AlertDialogFooter>
            <AlertDialogCancel className="cursor-pointer">Cancel</AlertDialogCancel>
            <AlertDialogAction
              className="cursor-pointer bg-duck-yellow hover:bg-duck-yellow/90 text-duck-teal font-bold"
              onClick={() => {
                if (confirmCommand) setRunCommand({ command: confirmCommand });
                setConfirmCommand(null);
              }}
            >
              Run
            </AlertDialogAction>
          </AlertDialogFooter>
        </AlertDialogContent>
      </AlertDialog>
    </>
  );
};

export const Resources = () => {
  const { resources } = useResources();
  const [selectedId] = useGlobal<string | null>('RESOURCE_SELECTED', null);
  const [showCatalog] = useGlobal<boolean>('RESOURCE_CATALOG', false);

  const resource = selectedId ? resources?.find((r: Resource) => r.id === selectedId) : null;

  if (showCatalog || !resource) return <ResourceCatalog />;
  return <ResourceDetail resource={resource} />;
};
