import { useState, useEffect, useRef } from 'react';
import { useQuery, useQueryClient } from '@tanstack/react-query';
import ReactMarkdown from 'react-markdown';
import remarkGfm from 'remark-gfm';
import rehypeRaw from 'rehype-raw';
import { toast } from 'sonner';
import { Pencil, Trash2, Plus, X, Loader2, ArrowLeft } from 'lucide-react';
import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription } from '@/components/ui/dialog';
import { useGlobal } from 'hooks/useGlobal';
import { useClient } from 'hooks/useClient';
import { usePiChat, EmbeddableChat } from 'officerdev';
import { useResources, type ResourceDetail, type PingResult } from 'state/useResources';
import { FrontmatterBlock } from '../../CapabilityPage';

const isSensitiveKey = (key: string) => /key|secret|password|token/i.test(key);

type ConfigEditorProps = {
  resourceName: string;
  config: Record<string, string>;
  onSaved: () => void;
};

const ConfigEditor = ({ resourceName, config, onSaved }: ConfigEditorProps) => {
  const { saveConfig, pingResource } = useResources();
  const configEntries = Object.entries(config);
  const [fields, setFields] = useState<[string, string][]>(configEntries);
  const [newKey, setNewKey] = useState('');
  const [newValue, setNewValue] = useState('');
  const [pinging, setPinging] = useState(false);
  const [pingResult, setPingResult] = useState<PingResult | null>(null);
  const [saving, setSaving] = useState(false);

  useEffect(() => {
    setFields(Object.entries(config));
  }, [config]);

  const hasUrl = fields.some(([k, v]) => k === 'url' && v);

  const handleAddField = () => {
    const key = newKey.trim();
    if (!key || fields.some(([k]) => k === key)) return;
    setFields([...fields, [key, newValue]]);
    setNewKey('');
    setNewValue('');
  };

  const handleRemoveField = (index: number) => {
    setFields(fields.filter((_, i) => i !== index));
  };

  const handleFieldValue = (index: number, value: string) => {
    setFields(fields.map((f, i) => (i === index ? [f[0]!, value] : f)));
  };

  const handlePing = async () => {
    const url = fields.find(([k]) => k === 'url')?.[1];
    if (!url) return;
    setPinging(true);
    setPingResult(null);
    try {
      const result = await pingResource(resourceName, url);
      setPingResult(result);
    } catch {
      setPingResult({ reachable: false, latencyMs: null });
    } finally {
      setPinging(false);
    }
  };

  const handleSave = async () => {
    setSaving(true);
    try {
      const oldKeys = Object.keys(config);
      const newKeys = new Set(fields.map(([k]) => k));
      const patch: Record<string, string | null> = {};
      for (const [key, value] of fields) {
        patch[key] = value;
      }
      for (const key of oldKeys) {
        if (!newKeys.has(key)) patch[key] = null;
      }
      await saveConfig(resourceName, patch);
      onSaved();
      toast.success('Configuration saved');
    } catch {
      toast.error('Failed to save configuration');
    } finally {
      setSaving(false);
    }
  };

  return (
    <div className="mb-6">
      <h3 className="text-sm font-semibold text-duck-dark mb-3">Configuration</h3>
      <div className="flex flex-col gap-2">
        {fields.map(([key, value], index) => (
          <div key={key} className="flex items-center gap-2">
            <label className="text-xs text-duck-dark/50 w-28 shrink-0 truncate" title={key}>
              {key}
            </label>
            <Input
              value={value}
              onChange={(ev) => handleFieldValue(index, ev.target.value)}
              type={isSensitiveKey(key) ? 'password' : 'text'}
              className="h-8 text-xs flex-1"
            />
            <Button
              variant="ghost"
              size="sm"
              className="h-8 w-8 p-0 shrink-0 text-duck-dark/30 hover:text-red-500 cursor-pointer"
              onClick={() => handleRemoveField(index)}
            >
              <X className="h-3 w-3" />
            </Button>
          </div>
        ))}
        <div className="flex items-center gap-2">
          <Input
            value={newKey}
            onChange={(ev) => setNewKey(ev.target.value)}
            placeholder="key"
            className="h-8 text-xs w-28 shrink-0"
            onKeyDown={(ev) => ev.key === 'Enter' && handleAddField()}
          />
          <Input
            value={newValue}
            onChange={(ev) => setNewValue(ev.target.value)}
            placeholder="value"
            className="h-8 text-xs flex-1"
            onKeyDown={(ev) => ev.key === 'Enter' && handleAddField()}
          />
          <Button
            variant="ghost"
            size="sm"
            className="h-8 w-8 p-0 shrink-0 text-duck-dark/30 hover:text-duck-teal cursor-pointer"
            onClick={handleAddField}
            disabled={!newKey.trim()}
          >
            <Plus className="h-3 w-3" />
          </Button>
        </div>
        <div className="flex items-center gap-2 mt-1">
          {hasUrl && (
            <Button variant="outline" size="sm" onClick={handlePing} disabled={pinging} className="text-xs cursor-pointer">
              {pinging && <Loader2 className="h-3 w-3 animate-spin mr-1" />}
              Test Connection
            </Button>
          )}
          <Button size="sm" onClick={handleSave} disabled={saving} className="text-xs cursor-pointer">
            {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 ResourceChatProps = {
  detail: ResourceDetail;
  isNew?: boolean;
  onResponseEnd: () => void;
};

const ResourceChat = ({ detail, isNew, onResponseEnd }: ResourceChatProps) => {
  const promptFrontmatter = `<frontmatter>\nconfig file: ${detail.configPath}\nresource file: ${detail.filePath}\nguide: ${detail.guidePath}\n\nYou are helping configure a resource. Read the GUIDE.md for instructions on how to help. Read the RESOURCE.md for context about what this resource is. Write config values to the config.json file.\n</frontmatter>`;
  const defaultInput = isNew
    ? 'Help me set up this new resource'
    : 'Help me configure this resource';

  const pi = usePiChat(undefined, undefined, { replaceUrl: false });

  const onResponseEndRef = useRef(onResponseEnd);
  onResponseEndRef.current = onResponseEnd;

  const wasGenerating = useRef(false);
  useEffect(() => {
    if (wasGenerating.current && !pi.isGenerating) {
      onResponseEndRef.current();
    }
    wasGenerating.current = pi.isGenerating;
  }, [pi.isGenerating]);

  return (
    <EmbeddableChat
      chat={pi}
      defaultInput={defaultInput}
      promptPrefix={promptFrontmatter}
      className="h-full"
    />
  );
};

export const Resources = () => {
  const client = useClient();
  const qc = useQueryClient();
  const [selectedName] = useGlobal<string | null>('RESOURCE_SELECTED', null);
  const [editing, setEditing] = useState(false);
  const [isNew, setIsNew] = useState(false);
  const [deleteConfirm, setDeleteConfirm] = useState(false);
  const [showDetail, setShowDetail] = useState(false);

  const { data: detail, refetch } = useQuery<ResourceDetail>({
    queryKey: ['RESOURCES', selectedName],
    queryFn: () => client.get<ResourceDetail>(`/server-settings/resources/${selectedName}`),
    enabled: !!selectedName,
  });

  useEffect(() => {
    if (selectedName) {
      setShowDetail(true);
      setEditing(false);
    }
  }, [selectedName]);

  const handleDelete = async () => {
    if (!selectedName) return;
    try {
      await client.delete(`/server-settings/resources/${selectedName}`);
      setDeleteConfirm(false);
      setEditing(false);
      await qc.invalidateQueries({ queryKey: ['RESOURCES'] });
    } catch {
      toast.error('Failed to delete resource');
    }
  };

  const canDelete = detail && detail.scope === 'global' && !detail.filePath.includes('/seed/');

  if (!selectedName || !detail) {
    return (
      <div className="h-full flex items-center justify-center">
        <p className="text-sm text-duck-dark/40">Select a resource to view its configuration</p>
      </div>
    );
  }

  return (
    <>
      <div className="flex flex-col h-full">
        {/* Detail panel */}
        <div className={`flex-1 overflow-hidden flex flex-col min-h-0 ${editing ? 'hidden md:flex' : ''}`}>
          <div className="shrink-0 px-4 py-2 border-b border-duck-dark/10 bg-background/60 flex items-center gap-2">
            <button
              onClick={() => setShowDetail(false)}
              className="md:hidden p-1 -ml-1 rounded hover:bg-duck-dark/10 cursor-pointer"
            >
              <ArrowLeft className="h-4 w-4 text-duck-dark/60" />
            </button>
            <span className="text-sm font-medium text-duck-dark/70 flex-1">{detail.name}</span>
            <span
              className={`shrink-0 text-[10px] px-1.5 py-0.5 rounded-full font-medium ${
                detail.scope === 'global' ? 'bg-duck-teal/20 text-duck-teal' : 'bg-duck-dark/10 text-duck-dark/60'
              }`}
            >
              {detail.scope}
            </span>
            <button
              onClick={() => setEditing((e) => !e)}
              className={`p-1 rounded hover:bg-duck-dark/10 cursor-pointer transition-colors ${editing ? 'bg-duck-teal/10' : ''}`}
            >
              <Pencil className={`h-3.5 w-3.5 ${editing ? 'text-duck-teal' : 'text-duck-dark/50'}`} />
            </button>
            {canDelete && (
              <button
                onClick={() => setDeleteConfirm(true)}
                className="p-1 rounded hover:bg-red-50 cursor-pointer transition-colors"
              >
                <Trash2 className="h-3.5 w-3.5 text-duck-dark/50 hover:text-red-500" />
              </button>
            )}
          </div>
          <div className="overflow-y-auto flex-1 p-6">
            {detail.rawFrontmatter && <FrontmatterBlock yaml={detail.rawFrontmatter} />}
            {detail.body && (
              <article className="skill-md mb-6">
                <ReactMarkdown remarkPlugins={[remarkGfm]} rehypePlugins={[rehypeRaw]}>
                  {detail.body}
                </ReactMarkdown>
              </article>
            )}
            <ConfigEditor
              key={selectedName}
              resourceName={selectedName}
              config={detail.config}
              onSaved={() => refetch()}
            />
          </div>
        </div>

        {/* Chat panel */}
        {editing && (
          <div className="flex-1 overflow-hidden flex flex-col min-h-0">
            <div className="shrink-0 px-4 py-1.5 border-b border-duck-dark/10 bg-background/60 flex items-center gap-2">
              <button
                onClick={() => setEditing(false)}
                className="md:hidden p-1 -ml-1 rounded hover:bg-duck-dark/10 cursor-pointer"
              >
                <ArrowLeft className="h-4 w-4 text-duck-dark/60" />
              </button>
              <span className="text-xs font-medium text-duck-dark/50 flex-1">{detail.name} — Chat</span>
              <button
                onClick={() => setEditing(false)}
                className="p-1 rounded hover:bg-duck-dark/10 cursor-pointer transition-colors"
              >
                <X className="h-3.5 w-3.5 text-duck-dark/50" />
              </button>
            </div>
            <ResourceChat
              key={detail.filePath}
              detail={detail}
              isNew={isNew}
              onResponseEnd={() => {
                refetch();
                qc.invalidateQueries({ queryKey: ['RESOURCES'] });
              }}
            />
          </div>
        )}
      </div>

      <Dialog open={deleteConfirm} onOpenChange={setDeleteConfirm}>
        <DialogContent className="sm:max-w-md z-[700]">
          <DialogHeader>
            <DialogTitle>Delete Resource</DialogTitle>
            <DialogDescription>
              Are you sure you want to delete &quot;{detail.name}&quot;? This action cannot be undone.
            </DialogDescription>
          </DialogHeader>
          <div className="flex justify-end gap-2 mt-2">
            <Button variant="outline" onClick={() => setDeleteConfirm(false)} className="cursor-pointer">
              Cancel
            </Button>
            <Button variant="destructive" onClick={handleDelete} className="cursor-pointer">
              Delete
            </Button>
          </div>
        </DialogContent>
      </Dialog>
    </>
  );
};
