import { useState, useEffect, useMemo, useCallback, type DragEvent } from 'react';
import { toast } from 'sonner';
import { Terminal, Eye, Bot, Settings, X, Plus } from 'lucide-react';
import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label';
import { Button } from '@/components/ui/button';
import { Textarea } from '@/components/ui/textarea';
import { Slider } from '@/components/ui/slider';
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
import { useQueryClient } from '@tanstack/react-query';
import type { LayoutNode, PanelComponents } from '@/components/Workspace';
import { WorkspaceLayout } from '@/components/Workspace';
import { usePanelChannel } from 'hooks/usePanelChannel';
import { TerminalView } from 'officerdev';
import { appRegistry } from '../Workspaces/app-registry';
import { createSettingsPanelComponents, type SettingsSectionGroup } from './SettingsPanel';
import { useSettings } from '@/state/useSettings';
import { useUserState } from '@/state/useUserState';
import { usePiModels, useVisiblePiModels, type ModelOption } from '@/state/useModels';
import type { UserSettings } from '@/state/types/user-settings';
import { AIHarnessesSection } from './ServerSettings/AIHarnessesSection';
import { RUN_COMMAND_CHANNEL, type RunCommandState } from './ServerSettings/run-command-channel';

const PROVIDER_DISPLAY: Record<string, string> = {
  anthropic: 'Anthropic',
  openai: 'OpenAI',
  opencode: 'OpenCode Zen',
  google: 'Google',
  groq: 'Groq',
  mistral: 'Mistral',
  xai: 'xAI',
  openrouter: 'OpenRouter',
  huggingface: 'Hugging Face',
  'github-copilot': 'GitHub Copilot',
  minimax: 'MiniMax',
  bedrock: 'Amazon Bedrock',
  'google-vertex': 'Google Vertex AI',
  'azure-openai': 'Azure OpenAI',
};

function displayProviderName(provider: string): string {
  return PROVIDER_DISPLAY[provider] ?? provider;
}

const groups: SettingsSectionGroup[] = [
  {
    label: 'AI',
    icon: Bot,
    sections: [
      { key: 'ai-harnesses', icon: Terminal, title: 'Providers', description: 'Remote and local AI providers', content: <AIHarnessesSection /> },
      { key: 'model-visibility', icon: Eye, title: 'Models', description: 'Enable or disable models', content: <ModelVisibilitySection /> },
      { key: 'chat-defaults', icon: Terminal, title: 'Chat Defaults', description: 'Model, prompt, and temperature', content: <ChatDefaultsSection /> },
    ],
  },
];

const { Sidebar, Content } = createSettingsPanelComponents({
  globalKey: 'SYSTEM_SETTINGS_SELECTED',
  sidebarIcon: Settings,
  sidebarLabel: 'System',
  groups,
});

const baseLayout: LayoutNode = {
  type: 'group',
  id: 'system-root',
  direction: 'horizontal',
  children: [
    { node: { type: 'panel', id: 'system-left', appType: null }, size: 20 },
    { node: { type: 'panel', id: 'system-right', appType: null }, size: 80 },
  ],
};

const splitLayout: LayoutNode = {
  type: 'group',
  id: 'system-root',
  direction: 'horizontal',
  children: [
    { node: { type: 'panel', id: 'system-left', appType: null }, size: 20 },
    {
      node: {
        type: 'group',
        id: 'system-right-group',
        direction: 'vertical',
        children: [
          { node: { type: 'panel', id: 'system-right', appType: null }, size: 50 },
          { node: { type: 'panel', id: 'system-terminal', appType: null }, size: 50 },
        ],
      },
      size: 80,
    },
  ],
};

const SystemTerminalPanel = () => {
  const queryClient = useQueryClient();
  const [state, setState] = usePanelChannel<RunCommandState>(RUN_COMMAND_CHANNEL, null);
  const [session, setSession] = useState<{ id: string; command: string } | null>(null);

  useEffect(() => {
    if (state && (!session || session.command !== state.command)) {
      setSession({ id: `run-cmd-${Date.now()}`, command: state.command });
    } else if (!state) {
      setSession(null);
    }
  }, [state]);

  const close = () => setState(null);

  const onCommandDone = (exitCode: number, output: string) => {
    if (state) {
      for (const key of state.refetchKeys) {
        queryClient.invalidateQueries({ queryKey: [key] });
      }
    }
    if (exitCode === 0) {
      toast.success('Command completed successfully');
    } else {
      toast.error(output || `Command failed with exit code ${exitCode}`, { duration: 8000 });
    }
    setState(null);
  };

  if (!state || !session) return null;

  return (
    <div className="h-full flex flex-col">
      <div className="shrink-0 px-4 py-1.5 border-b border-duck-dark/10 dark:border-foreground/10 bg-background/60 flex items-center gap-2">
        <span className="text-xs font-medium text-duck-dark/50 dark:text-foreground/50 flex-1">Run Command</span>
        <button onClick={close} className="p-1 rounded hover:bg-duck-dark/10 dark:hover:bg-foreground/10 cursor-pointer transition-colors">
          <X className="h-3.5 w-3.5 text-duck-dark/50 dark:text-foreground/50" />
        </button>
      </div>
      <TerminalView
        className="flex-1"
        sandboxed={false}
        command={session.command}
        sessionId={session.id}
        onCommandDone={onCommandDone}
      />
    </div>
  );
};

export const SystemSettings = () => {
  const [runCommand] = usePanelChannel<RunCommandState>(RUN_COMMAND_CHANNEL, null);

  const layout = useMemo(() => (runCommand ? splitLayout : baseLayout), [runCommand]);

  const panelComponents: PanelComponents = useMemo(
    () => ({
      'system-left': Sidebar,
      'system-right': Content,
      'system-terminal': SystemTerminalPanel,
    }),
    [],
  );

  return (
    <div className="h-full w-full pt-2">
      <WorkspaceLayout layout={layout} onLayoutChange={() => {}} registry={appRegistry} components={panelComponents} />
    </div>
  );
};

// --- AI sections ---

function ChatDefaultsSection() {
  const { settings, saveSettings } = useSettings();
  const piModels = useVisiblePiModels();
  const [isSaving, setIsSaving] = useState(false);

  const [model, setModel] = useState<string | null>(settings.chat.defaultModel);
  const [systemPrompt, setSystemPrompt] = useState(settings.chat.systemPrompt);
  const [temperature, setTemperature] = useState(settings.chat.temperature);
  const [defaultPwd, setDefaultPwd] = useState(settings.chat.defaultPwd);

  useEffect(() => {
    setModel(settings.chat.defaultModel);
    setSystemPrompt(settings.chat.systemPrompt);
    setTemperature(settings.chat.temperature);
    setDefaultPwd(settings.chat.defaultPwd);
  }, [settings]);

  const handleSave = async () => {
    if (isSaving) return;
    setIsSaving(true);
    try {
      const updated: UserSettings = {
        ...settings,
        chat: { defaultProvider: 'pi', defaultModel: model, systemPrompt, temperature, defaultPwd },
      };
      await saveSettings(updated);
      toast.success('Chat defaults saved');
    } catch {
      toast.error('Failed to save settings');
    } finally {
      setIsSaving(false);
    }
  };

  return (
    <div className="grid gap-4">
      <Label className="grid gap-2">
        <span className="text-duck-dark/70">Model</span>
        <Select value={model ?? ''} onValueChange={(v) => setModel(v || null)}>
          <SelectTrigger className="h-11 bg-background/60 border-duck-dark/20 text-duck-dark">
            <SelectValue placeholder="Default" />
          </SelectTrigger>
          <SelectContent className="z-[600]">
            {piModels.map((m: ModelOption) => (
              <SelectItem key={m.id} value={m.id}>
                <span className="font-bold">{m.name}</span>
                {m.provider && <span className="text-duck-dark/50 ml-1">({m.provider})</span>}
              </SelectItem>
            ))}
          </SelectContent>
        </Select>
      </Label>

      <Label className="grid gap-2">
        <span className="text-duck-dark/70">System Prompt</span>
        <Textarea
          className="bg-background/60 border-duck-dark/20 text-duck-dark placeholder:text-duck-dark/40 min-h-[100px]"
          placeholder="Custom instructions for the AI..."
          value={systemPrompt}
          onChange={(ev) => setSystemPrompt(ev.target.value)}
        />
      </Label>

      <Label className="grid gap-2">
        <div className="flex items-center justify-between">
          <span className="text-duck-dark/70">Temperature</span>
          <span className="text-sm text-duck-dark/50">{temperature.toFixed(1)}</span>
        </div>
        <Slider min={0} max={2} step={0.1} value={[temperature]} onValueChange={([v]) => setTemperature(v ?? 1)} />
      </Label>

      <Label className="grid gap-2">
        <span className="text-duck-dark/70">Default Working Directory</span>
        <Input
          className="h-11 bg-background/60 border-duck-dark/20 text-duck-dark placeholder:text-duck-dark/40"
          value={defaultPwd}
          onChange={(ev) => setDefaultPwd(ev.target.value)}
          placeholder="~"
        />
      </Label>

      <Button
        type="button"
        onClick={handleSave}
        disabled={isSaving}
        className="w-full h-11 bg-duck-yellow hover:bg-duck-yellow/90 text-duck-teal font-bold transition-all duration-200 hover:scale-105 cursor-pointer disabled:opacity-50 disabled:hover:scale-100"
      >
        {isSaving ? 'Saving...' : 'Save'}
      </Button>
    </div>
  );
}

type ModelPillProps = {
  label: string;
  modelKey: string;
  enabled: boolean;
  onAction: (key: string) => void;
  onDragStart: (ev: DragEvent, key: string) => void;
};

const ModelPill = ({ label, modelKey, enabled, onAction, onDragStart }: ModelPillProps) => (
  <span
    draggable
    onDragStart={(ev) => onDragStart(ev, modelKey)}
    className="inline-flex items-center gap-1 px-2.5 py-1 rounded-full text-xs font-medium cursor-grab active:cursor-grabbing select-none border border-duck-dark/15 dark:border-foreground/15 bg-background/60 text-duck-dark/80 dark:text-foreground/80 hover:bg-duck-dark/5 dark:hover:bg-foreground/5 transition-colors"
  >
    {label}
    <button
      onClick={() => onAction(modelKey)}
      className="ml-0.5 p-0.5 rounded-full hover:bg-duck-dark/10 dark:hover:bg-foreground/10 cursor-pointer transition-colors"
    >
      {enabled ? <X className="h-3 w-3" /> : <Plus className="h-3 w-3" />}
    </button>
  </span>
);

type DropZoneProps = {
  label: string;
  children: React.ReactNode;
  onDrop: (key: string) => void;
};

const DropZone = ({ label, children, onDrop }: DropZoneProps) => {
  const [over, setOver] = useState(false);

  const handleDragOver = useCallback((ev: DragEvent) => {
    ev.preventDefault();
    setOver(true);
  }, []);

  const handleDragLeave = useCallback(() => setOver(false), []);

  const handleDrop = useCallback(
    (ev: DragEvent) => {
      ev.preventDefault();
      setOver(false);
      const key = ev.dataTransfer.getData('text/plain');
      if (key) onDrop(key);
    },
    [onDrop],
  );

  return (
    <div className="grid gap-1.5">
      <span className="text-xs font-medium text-duck-dark/50 dark:text-foreground/50 uppercase tracking-wide">{label}</span>
      <div
        onDragOver={handleDragOver}
        onDragLeave={handleDragLeave}
        onDrop={handleDrop}
        className={`min-h-[48px] p-2 rounded-lg border border-dashed transition-colors flex flex-wrap gap-1.5 ${over ? 'border-duck-teal bg-duck-teal/5' : 'border-duck-dark/15 dark:border-foreground/15'}`}
      >
        {children}
      </div>
    </div>
  );
};

function ModelVisibilitySection() {
  const { settings, saveSettings } = useSettings();
  const piModels = usePiModels();
  const [activeProvider, setActiveProvider] = useUserState<string>('model-visibility-provider', '');

  const enabledModels = settings.ai?.enabledModels ?? [];

  const providerGroups = useMemo(() => {
    const groups: Record<string, { id: string; name: string }[]> = {};
    for (const m of piModels) {
      const provider = m.provider ?? 'Other';
      if (!groups[provider]) groups[provider] = [];
      groups[provider].push({ id: m.id, name: m.name });
    }
    return Object.entries(groups)
      .sort(([a], [b]) => a.localeCompare(b))
      .map(([provider, models]) => ({ provider, models: models.sort((a, b) => a.name.localeCompare(b.name)) }));
  }, [piModels]);

  const providers = useMemo(() => providerGroups.map((g) => g.provider), [providerGroups]);

  // Auto-select first provider if none selected or stale
  const selected = providers.includes(activeProvider) ? activeProvider : providers[0] ?? '';

  const currentGroup = providerGroups.find((g) => g.provider === selected);

  const { enabled, disabled } = useMemo(() => {
    if (!currentGroup) return { enabled: [], disabled: [] };
    const en: { id: string; name: string; key: string }[] = [];
    const dis: { id: string; name: string; key: string }[] = [];
    for (const m of currentGroup.models) {
      const key = `${currentGroup.provider}:${m.id}`;
      if (enabledModels.includes(key)) {
        en.push({ ...m, key });
      } else {
        dis.push({ ...m, key });
      }
    }
    return { enabled: en, disabled: dis };
  }, [currentGroup, enabledModels]);

  const enableModel = useCallback(
    async (key: string) => {
      if (enabledModels.includes(key)) return;
      await saveSettings({ ...settings, ai: { ...settings.ai, enabledModels: [...enabledModels, key] } });
    },
    [settings, enabledModels, saveSettings],
  );

  const disableModel = useCallback(
    async (key: string) => {
      await saveSettings({ ...settings, ai: { ...settings.ai, enabledModels: enabledModels.filter((id) => id !== key) } });
    },
    [settings, enabledModels, saveSettings],
  );

  const onDragStart = useCallback((ev: DragEvent, key: string) => {
    ev.dataTransfer.setData('text/plain', key);
    ev.dataTransfer.effectAllowed = 'move';
  }, []);

  if (providerGroups.length === 0) {
    return <p className="text-sm text-duck-dark/40 dark:text-foreground/40">No models available. Configure API keys in AI Settings.</p>;
  }

  return (
    <div className="grid gap-4">
      {/* Provider tabs */}
      <div className="flex flex-wrap gap-1 border-b border-duck-dark/10 dark:border-foreground/10 pb-1">
        {providers.map((p) => (
          <button
            key={p}
            onClick={() => setActiveProvider(p)}
            className={`px-3 py-1.5 text-sm font-medium rounded-t-md transition-colors cursor-pointer ${
              p === selected
                ? 'bg-duck-teal/10 text-duck-teal border-b-2 border-duck-teal'
                : 'text-duck-dark/50 dark:text-foreground/50 hover:text-duck-dark dark:hover:text-foreground hover:bg-duck-dark/5 dark:hover:bg-foreground/5'
            }`}
          >
            {displayProviderName(p)}
          </button>
        ))}
      </div>

      {/* Enabled section */}
      <DropZone label="Enabled" onDrop={enableModel}>
        {enabled.length === 0 && <span className="text-xs text-duck-dark/30 dark:text-foreground/30 py-1">Drag models here to enable</span>}
        {enabled.map((m) => (
          <ModelPill key={m.key} label={m.name} modelKey={m.key} enabled onAction={disableModel} onDragStart={onDragStart} />
        ))}
      </DropZone>

      {/* Disabled section */}
      <DropZone label="Disabled" onDrop={disableModel}>
        {disabled.length === 0 && <span className="text-xs text-duck-dark/30 dark:text-foreground/30 py-1">All models enabled</span>}
        {disabled.map((m) => (
          <ModelPill key={m.key} label={m.name} modelKey={m.key} enabled={false} onAction={enableModel} onDragStart={onDragStart} />
        ))}
      </DropZone>
    </div>
  );
}
