import * as React from 'react';
import { useState } from 'react';
import { useParams, Link } from 'react-router-dom';
import { api, type Personality, type PersonalityPrompt, type Prompt } from '../api';
import { useFetch } from '../hooks/useFetch';

/**
 * Personality detail: show metadata, list bound prompts (with priority
 * within this overlay), and offer an "attach prompt" picker that lets the
 * user select from in-scope candidates (agent-direct + same-project + global).
 */
export function PersonalityDetailPage(): React.JSX.Element {
  const { id } = useParams<{ id: string }>();
  const personalityId = id ?? '';

  const personality = useFetch(
    () => api.get<Personality>(`/api/v1/personalities/${encodeURIComponent(personalityId)}`),
    [personalityId],
  );
  const bindings = useFetch(
    () => api.get<PersonalityPrompt[]>(`/api/v1/personalities/${encodeURIComponent(personalityId)}/prompts`),
    [personalityId],
  );

  if (personality.loading || bindings.loading) return <div>Loading…</div>;
  if (personality.error !== null) return <div style={{ color: '#ff7b72' }}>Error: {personality.error.message}</div>;
  if (personality.data === null) return <div>Not found.</div>;

  const p = personality.data;
  const bound = bindings.data ?? [];

  return (
    <section>
      <p style={{ marginTop: 0 }}>
        <Link to={`/agents/${encodeURIComponent(p.agentName)}`} style={{ color: '#58a6ff' }}>
          ← {p.agentName}
        </Link>
      </p>
      <h2 style={{ marginTop: 0 }}>
        {p.name}
        <span style={{ color: '#7d8590', fontSize: 14, marginLeft: 12 }}>personality on {p.agentName}</span>
      </h2>
      {p.description !== '' && <p style={{ color: '#c9d1d9' }}>{p.description}</p>}

      <h3>Bound prompts ({bound.length})</h3>
      <p style={{ color: '#7d8590', marginTop: 0 }}>
        Activated when this personality is selected at chat time. Priority controls order within
        the overlay (higher first).
      </p>
      {bound.length === 0 && <p style={{ color: '#7d8590' }}>No bound prompts yet.</p>}
      <ul style={{ listStyle: 'none', padding: 0, margin: 0 }}>
        {bound
          .slice()
          .sort((a, b) => b.priority - a.priority)
          .map((b) => (
            <li key={b.promptId} style={card}>
              <div style={cardHeader}>
                <div>
                  <strong style={{ fontFamily: 'ui-monospace, monospace' }}>{b.promptName}</strong>
                  <span style={{ color: '#7d8590', marginLeft: 8, fontSize: 12 }}>priority {b.priority}</span>
                </div>
                <button onClick={() => detach(personalityId, b.promptId, b.promptName, bindings.refetch)} style={dangerBtn}>
                  Detach
                </button>
              </div>
              <pre style={contentPre}>{b.promptContent}</pre>
            </li>
          ))}
      </ul>

      <AttachPromptPanel
        personality={p}
        boundPromptIds={bound.map((b) => b.promptId)}
        onAttached={bindings.refetch}
      />
    </section>
  );
}

async function detach(
  personalityId: string,
  promptId: string,
  promptName: string,
  refetch: () => void,
): Promise<void> {
  if (!confirm(`Detach prompt '${promptName}' from this personality?`)) return;
  await api.delete(`/api/v1/personalities/${personalityId}/prompts/${promptId}`);
  refetch();
}

// ── Attach picker ──

function AttachPromptPanel(props: {
  personality: Personality;
  boundPromptIds: string[];
  onAttached: () => void;
}): React.JSX.Element {
  const [open, setOpen] = useState(false);
  const candidates = useFetch(
    async () => {
      // In-scope candidates: agent-direct + same-project + global.
      const direct = await api.get<Prompt[]>(
        `/api/v1/agents/${encodeURIComponent(props.personality.agentName)}/prompts`,
      );
      const agentRow = await api.get<{ project: { name: string } | null }>(
        `/api/v1/agents/${encodeURIComponent(props.personality.agentName)}`,
      );
      let projectAndGlobal: Prompt[] = [];
      if (agentRow.project !== null) {
        projectAndGlobal = await api.get<Prompt[]>(
          `/api/v1/prompts?project=${encodeURIComponent(agentRow.project.name)}`,
        );
      } else {
        projectAndGlobal = await api.get<Prompt[]>(`/api/v1/prompts?scope=global`);
      }
      // Dedupe; exclude ones already bound.
      const seen = new Set<string>(props.boundPromptIds);
      const merged: Prompt[] = [];
      for (const p of [...direct, ...projectAndGlobal]) {
        if (seen.has(p.id)) continue;
        seen.add(p.id);
        merged.push(p);
      }
      return merged;
    },
    [props.personality.id, props.boundPromptIds.join(',')],
  );

  const [busyId, setBusyId] = useState<string | null>(null);
  async function attach(promptId: string): Promise<void> {
    setBusyId(promptId);
    try {
      await api.post(`/api/v1/personalities/${props.personality.id}/prompts`, { promptId });
      props.onAttached();
    } catch (err) {
      alert((err as Error).message);
    } finally {
      setBusyId(null);
    }
  }

  if (!open) {
    return <button onClick={() => setOpen(true)} style={primaryBtn}>+ Attach prompt</button>;
  }

  return (
    <div style={card}>
      <h3 style={{ marginTop: 0 }}>Attach a prompt</h3>
      <p style={{ color: '#7d8590', marginTop: 0 }}>
        Eligible: prompts on this agent, prompts in the agent's project, or globals.
      </p>
      {candidates.loading && <div>Loading candidates…</div>}
      {candidates.error !== null && <div style={{ color: '#ff7b72' }}>Error: {candidates.error.message}</div>}
      <ul style={{ listStyle: 'none', padding: 0, margin: 0 }}>
        {(candidates.data ?? []).map((p) => (
          <li key={p.id} style={{ display: 'flex', justifyContent: 'space-between', padding: '8px 0', borderBottom: '1px solid #30363d' }}>
            <div>
              <strong style={{ fontFamily: 'ui-monospace, monospace' }}>{p.name}</strong>
              <span style={{ color: '#7d8590', marginLeft: 8, fontSize: 12 }}>
                {p.agentId !== null ? 'agent-direct' : p.projectId !== null ? 'project' : 'global'}
              </span>
            </div>
            <button onClick={() => attach(p.id)} disabled={busyId === p.id} style={secondaryBtn}>
              {busyId === p.id ? 'Attaching…' : 'Attach'}
            </button>
          </li>
        ))}
        {(candidates.data ?? []).length === 0 && !candidates.loading && (
          <li style={{ color: '#7d8590', padding: '8px 0' }}>No eligible prompts to attach.</li>
        )}
      </ul>
      <button onClick={() => setOpen(false)} style={secondaryBtn}>Close</button>
    </div>
  );
}

const card: React.CSSProperties = {
  background: '#161b22',
  border: '1px solid #30363d',
  borderRadius: 6,
  padding: 16,
  margin: '12px 0',
};
const cardHeader: React.CSSProperties = {
  display: 'flex',
  justifyContent: 'space-between',
  alignItems: 'center',
  marginBottom: 8,
};
const contentPre: React.CSSProperties = {
  background: '#0d1117',
  color: '#c9d1d9',
  padding: 12,
  borderRadius: 4,
  margin: 0,
  whiteSpace: 'pre-wrap',
  fontFamily: 'ui-monospace, "SF Mono", Menlo, monospace',
  fontSize: 12,
};
const primaryBtn: React.CSSProperties = {
  background: '#238636',
  color: '#fff',
  border: 'none',
  borderRadius: 4,
  padding: '8px 16px',
  cursor: 'pointer',
  fontWeight: 600,
};
const secondaryBtn: React.CSSProperties = {
  background: 'transparent',
  color: '#c9d1d9',
  border: '1px solid #30363d',
  borderRadius: 4,
  padding: '4px 12px',
  cursor: 'pointer',
};
const dangerBtn: React.CSSProperties = {
  background: 'transparent',
  color: '#ff7b72',
  border: '1px solid #f85149',
  borderRadius: 4,
  padding: '4px 12px',
  cursor: 'pointer',
};
