import { useState } from 'react';
import { useTranslation, Trans } from 'react-i18next';
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
import { useAuthState } from '../../App';

interface ServerPublic {
  id: string;
  name: string;
  url: string;
  authKind: 'oauth' | 'api_key';
  ownerId: string | null;
  oauthClientId: string | null;
  oauthScopes: string | null;
  authHeaderName: string | null;
  enabled: boolean;
  createdAt: string;
  updatedAt: string;
  toolCount?: number;
}

interface ConnectionRow {
  serverId: string;
  serverName: string;
  connected: boolean;
  authKind: 'oauth' | 'api_key';
  ownerId: string | null;
}

interface ServerFormBody {
  id: string;
  name: string;
  url: string;
  authKind: 'oauth' | 'api_key';
  oauthClientId?: string;
  oauthClientSecret?: string;
  oauthScopes?: string;
  staticToken?: string;
  authHeaderName?: string;
  enabled?: boolean;
}

// ── API helpers ───────────────────────────────────────────────────────────

async function fetchAdminServers(): Promise<ServerPublic[]> {
  const res = await fetch('/api/mcp/servers', { credentials: 'include' });
  if (!res.ok) throw new Error(`${res.status}`);
  return ((await res.json()) as { servers: ServerPublic[] }).servers ?? [];
}

async function fetchUserServers(): Promise<ServerPublic[]> {
  const res = await fetch('/api/mcp/user-servers', { credentials: 'include' });
  if (!res.ok) throw new Error(`${res.status}`);
  return ((await res.json()) as { servers: ServerPublic[] }).servers ?? [];
}

async function fetchConnections(): Promise<ConnectionRow[]> {
  const res = await fetch('/api/mcp/connections', { credentials: 'include' });
  if (!res.ok) throw new Error(`${res.status}`);
  return ((await res.json()) as { connections: ConnectionRow[] }).connections ?? [];
}

async function upsertServer(body: ServerFormBody, isGlobal: boolean): Promise<void> {
  const url = isGlobal ? '/api/mcp/servers' : '/api/mcp/user-servers';
  const res = await fetch(url, {
    method: 'POST', credentials: 'include',
    headers: { 'content-type': 'application/json' },
    body: JSON.stringify(body),
  });
  if (!res.ok) {
    const text = await res.text().catch(() => '');
    throw new Error(`${res.status} ${text}`);
  }
}

async function deleteServer(id: string, isGlobal: boolean): Promise<void> {
  const url = isGlobal
    ? `/api/mcp/servers/${encodeURIComponent(id)}`
    : `/api/mcp/user-servers/${encodeURIComponent(id)}`;
  const res = await fetch(url, { method: 'DELETE', credentials: 'include' });
  if (!res.ok) throw new Error(`${res.status}`);
}

async function refreshTools(id: string, isGlobal: boolean): Promise<void> {
  const url = isGlobal
    ? `/api/mcp/servers/${encodeURIComponent(id)}/tools/refresh`
    : `/api/mcp/user-servers/${encodeURIComponent(id)}/tools/refresh`;
  const res = await fetch(url, { method: 'POST', credentials: 'include' });
  if (!res.ok) throw new Error(`${res.status}`);
}

async function disconnectMcp(serverId: string): Promise<void> {
  const res = await fetch(`/api/mcp/connections/${encodeURIComponent(serverId)}`, {
    method: 'DELETE', credentials: 'include',
  });
  if (!res.ok) throw new Error(`${res.status}`);
}

// ── Sub-components ──────────────────────────────────────────────────────

function FormField({ label, children }: { label: string; children: React.ReactNode }) {
  return (
    <label className="block">
      <span className="block text-2xs text-slate-600 mb-1">{label}</span>
      {children}
    </label>
  );
}

const INPUT_CLS = 'w-full border border-hairline rounded px-2 py-1 text-[13px]';

const emptyForm = (): ServerFormBody => ({
  id: '', name: '', url: '', authKind: 'oauth',
  oauthClientId: '', oauthClientSecret: '', oauthScopes: '', staticToken: '', authHeaderName: '',
});

function ServerForm({
  initial,
  isEdit,
  sectionLabel,
  onSubmit,
  onCancel,
  isPending,
}: {
  initial: ServerFormBody;
  isEdit: boolean;
  sectionLabel: string;
  onSubmit: (body: ServerFormBody) => Promise<void>;
  onCancel?: () => void;
  isPending: boolean;
}) {
  const { t } = useTranslation('userfolder');
  const [form, setForm] = useState<ServerFormBody>(initial);
  const [formError, setFormError] = useState<string | null>(null);

  const handleSubmit = async (e: React.FormEvent) => {
    e.preventDefault();
    setFormError(null);
    try {
      await onSubmit(form);
      if (!isEdit) setForm(emptyForm());
    } catch (err) {
      setFormError(err instanceof Error ? err.message : String(err));
    }
  };

  return (
    <form className="space-y-3 max-w-xl" onSubmit={handleSubmit}>
      <FormField label={t('mcp.form.id')}>
        <input className={INPUT_CLS} value={form.id}
          onChange={(e) => setForm({ ...form, id: e.target.value })}
          placeholder="canva" pattern="[a-z0-9_-]{1,64}" required disabled={isEdit}
        />
      </FormField>
      <FormField label={t('mcp.form.name')}>
        <input className={INPUT_CLS} value={form.name}
          onChange={(e) => setForm({ ...form, name: e.target.value })}
          placeholder="Canva" required
        />
      </FormField>
      <FormField label={t('mcp.form.url')}>
        <input className={INPUT_CLS} value={form.url}
          onChange={(e) => setForm({ ...form, url: e.target.value })}
          placeholder="https://example.com/mcp" type="url" required
        />
      </FormField>

      <fieldset>
        <legend className="block text-2xs text-slate-600 mb-1">{t('mcp.form.authKind')}</legend>
        <div className="flex gap-4">
          <label className="flex items-center gap-1.5 text-[13px] cursor-pointer">
            <input type="radio" name={`authKind-${sectionLabel}`} value="oauth"
              checked={form.authKind === 'oauth'}
              onChange={() => setForm({ ...form, authKind: 'oauth' })}
              disabled={isEdit}
            /> OAuth
          </label>
          <label className="flex items-center gap-1.5 text-[13px] cursor-pointer">
            <input type="radio" name={`authKind-${sectionLabel}`} value="api_key"
              checked={form.authKind === 'api_key'}
              onChange={() => setForm({ ...form, authKind: 'api_key' })}
              disabled={isEdit}
            /> API key
          </label>
        </div>
      </fieldset>

      {form.authKind === 'oauth' && (
        <>
          <FormField label={t('mcp.form.oauthClientId')}>
            <input className={INPUT_CLS} value={form.oauthClientId ?? ''}
              onChange={(e) => setForm({ ...form, oauthClientId: e.target.value })}
              required={!isEdit}
            />
          </FormField>
          <FormField label={isEdit ? t('mcp.form.oauthClientSecretEdit') : t('mcp.form.oauthClientSecret')}>
            <input className={INPUT_CLS} type="password" value={form.oauthClientSecret ?? ''}
              onChange={(e) => setForm({ ...form, oauthClientSecret: e.target.value })}
              required={!isEdit}
            />
          </FormField>
          <FormField label={t('mcp.form.scopes')}>
            <input className={INPUT_CLS} value={form.oauthScopes ?? ''}
              onChange={(e) => setForm({ ...form, oauthScopes: e.target.value })}
              placeholder="read write"
            />
          </FormField>
        </>
      )}

      {form.authKind === 'api_key' && (
        <>
          <FormField label={isEdit ? t('mcp.form.apiKeyEdit') : t('mcp.form.apiKey')}>
            <input className={INPUT_CLS} type="password" value={form.staticToken ?? ''}
              onChange={(e) => setForm({ ...form, staticToken: e.target.value })}
              placeholder="sk-..." required={!isEdit}
            />
          </FormField>
          <FormField label={t('mcp.form.authHeaderName')}>
            <input className={`${INPUT_CLS} font-mono`} value={form.authHeaderName ?? ''}
              onChange={(e) => setForm({ ...form, authHeaderName: e.target.value })}
              placeholder="xc-mcp-token"
            />
            <span className="block text-[11px] text-slate-400 mt-1">
              <Trans t={t} i18nKey="mcp.form.authHeaderHelp" components={{ code: <code className="font-mono" /> }} />
            </span>
          </FormField>
        </>
      )}

      {formError && <div className="text-xs text-red-600">{formError}</div>}
      <div className="flex gap-2">
        <button type="submit" disabled={isPending}
          className="px-4 py-1.5 rounded-md text-xs font-semibold bg-accent text-accent-fg hover:bg-accent-deep transition-colors disabled:opacity-50">
          {isPending ? t('mcp.form.saving') : isEdit ? t('mcp.form.update') : t('mcp.form.add')}
        </button>
        {onCancel && (
          <button type="button" onClick={onCancel}
            className="px-4 py-1.5 rounded-md text-xs text-slate-700 border border-hairline hover:bg-surface transition-colors">
            {t('mcp.form.cancel')}
          </button>
        )}
      </div>
    </form>
  );
}

function ScopeBadge({ ownerId }: { ownerId: string | null }) {
  return ownerId === null ? (
    <span className="inline-block px-1.5 py-0.5 rounded text-[10px] font-medium bg-slate-100 text-slate-500 leading-none">global</span>
  ) : (
    <span className="inline-block px-1.5 py-0.5 rounded text-[10px] font-medium bg-blue-50 dark:bg-blue-500/15 text-blue-600 dark:text-blue-300 leading-none">personal</span>
  );
}

function ConnectionBadge({ connection, serverId }: { connection?: ConnectionRow; serverId: string }) {
  const { t } = useTranslation('userfolder');
  if (!connection) return <span className="text-2xs text-slate-400">—</span>;
  if (connection.authKind === 'api_key') {
    return connection.connected
      ? <span className="text-2xs text-emerald-600 font-medium">{t('mcp.connection.apiKeyConnected')}</span>
      : <span className="text-2xs text-amber-600">{t('mcp.connection.apiKeyMissing')}</span>;
  }
  if (connection.connected) {
    return <span className="text-2xs text-emerald-600 font-medium">{t('mcp.connection.oauthConnected')}</span>;
  }
  return (
    <a className="px-2 py-0.5 rounded text-2xs font-semibold bg-accent text-accent-fg hover:bg-accent-deep transition-colors"
      href={`/auth/mcp/${encodeURIComponent(serverId)}/start`}>
      {t('mcp.connection.connect')}
    </a>
  );
}

// ── Main component ──────────────────────────────────────────────────────

type ShowToast = (message: string, variant?: 'success' | 'error') => void;

export function McpPanel({ showToast }: { showToast?: ShowToast }) {
  const { t } = useTranslation('userfolder');
  const qc = useQueryClient();
  const auth = useAuthState();
  const isAdmin = auth.mode === 'authenticated' ? auth.user.role === 'admin' : true;

  const [editingId, setEditingId] = useState<string | null>(null);
  const [addingSection, setAddingSection] = useState<'global' | 'personal' | null>(null);

  const invalidateAll = () => {
    qc.invalidateQueries({ queryKey: ['mcp-servers-admin'] });
    qc.invalidateQueries({ queryKey: ['mcp-user-servers'] });
    qc.invalidateQueries({ queryKey: ['mcp-connections'] });
  };

  const { data: globalServers, isLoading: globalLoading } = useQuery({
    queryKey: ['mcp-servers-admin'], queryFn: fetchAdminServers,
    staleTime: 30_000, enabled: isAdmin,
  });
  const { data: userServers, isLoading: userLoading } = useQuery({
    queryKey: ['mcp-user-servers'], queryFn: fetchUserServers, staleTime: 30_000,
  });
  const { data: connections } = useQuery({
    queryKey: ['mcp-connections'], queryFn: fetchConnections, staleTime: 30_000,
  });

  const connMap = new Map((connections ?? []).map(c => [c.serverId, c]));

  const saveMut = useMutation({
    mutationFn: ({ body, isGlobal }: { body: ServerFormBody; isGlobal: boolean }) =>
      upsertServer(body, isGlobal),
    onSuccess: () => { invalidateAll(); setEditingId(null); setAddingSection(null); },
    onError: (err) => showToast?.(t('mcp.saveFailed', { error: err instanceof Error ? err.message : String(err) }), 'error'),
  });

  const delMut = useMutation({
    mutationFn: ({ id, isGlobal }: { id: string; isGlobal: boolean }) => deleteServer(id, isGlobal),
    onSuccess: invalidateAll,
  });

  const refreshMut = useMutation({
    mutationFn: ({ id, isGlobal }: { id: string; isGlobal: boolean }) => refreshTools(id, isGlobal),
    onSuccess: invalidateAll,
    onError: (err) => showToast?.(t('mcp.refreshFailed', { error: err instanceof Error ? err.message : String(err) }), 'error'),
  });

  const disconnectMut = useMutation({
    mutationFn: disconnectMcp,
    onSuccess: invalidateAll,
  });

  const handleDelete = (id: string, name: string, isGlobal: boolean) => {
    const msg = isGlobal ? t('mcp.confirmDeleteGlobal', { id }) : t('mcp.confirmDeletePersonal', { name });
    if (window.confirm(msg)) delMut.mutate({ id, isGlobal });
  };

  const renderServerRow = (s: ServerPublic, isGlobal: boolean) => {
    const conn = connMap.get(s.id);
    const isEditing = editingId === s.id;

    if (isEditing) {
      return (
        <div key={s.id} className="p-3 bg-surface/50 border border-hairline rounded-md">
          <ServerForm
            initial={{ id: s.id, name: s.name, url: s.url, authKind: s.authKind,
              oauthClientId: s.oauthClientId ?? '', oauthClientSecret: '', oauthScopes: s.oauthScopes ?? '',
              staticToken: '', authHeaderName: s.authHeaderName ?? '', enabled: s.enabled }}
            isEdit sectionLabel={`edit-${s.id}`}
            onSubmit={async (body) => { await saveMut.mutateAsync({ body, isGlobal }); }}
            onCancel={() => setEditingId(null)}
            isPending={saveMut.isPending}
          />
        </div>
      );
    }

    return (
      <div key={s.id} className="flex items-center gap-3 py-2.5 border-b border-hairline last:border-b-0">
        <div className="min-w-0 flex-1">
          <div className="flex items-center gap-1.5">
            <span className="text-[13px] font-medium text-slate-900">{s.name}</span>
            <ScopeBadge ownerId={s.ownerId} />
            <span className={`inline-block px-1.5 py-0.5 rounded text-[10px] font-medium leading-none ${
              s.authKind === 'oauth' ? 'bg-purple-50 dark:bg-purple-500/15 text-purple-600 dark:text-purple-300' : 'bg-amber-50 dark:bg-amber-500/15 text-amber-600 dark:text-amber-300'
            }`}>{s.authKind === 'oauth' ? 'OAuth' : 'API key'}</span>
            {s.toolCount != null && s.toolCount > 0 && (
              <span className="inline-block px-1.5 py-0.5 rounded text-[10px] font-medium bg-green-50 dark:bg-green-500/15 text-green-700 dark:text-green-300 leading-none">
                {t('mcp.toolCount', { count: s.toolCount })}
              </span>
            )}
          </div>
          <div className="text-2xs text-slate-500 font-mono truncate mt-0.5">{s.url}</div>
        </div>

        <div className="flex items-center gap-2 flex-shrink-0">
          <ConnectionBadge connection={conn} serverId={s.id} />

          {conn?.connected && conn.authKind === 'oauth' && (
            <button type="button" className="text-2xs text-slate-500 hover:text-slate-700 underline"
              onClick={() => { if (window.confirm(t('mcp.confirmDisconnect', { name: s.name }))) disconnectMut.mutate(s.id); }}
              disabled={disconnectMut.isPending}>
              {t('mcp.row.disconnect')}
            </button>
          )}

          <button type="button" className="text-2xs text-slate-600 hover:text-slate-800 underline"
            onClick={() => refreshMut.mutate({ id: s.id, isGlobal })}
            disabled={refreshMut.isPending}>
            {t('mcp.row.refreshTools')}
          </button>
          <button type="button" className="text-2xs text-slate-600 hover:text-slate-800 underline"
            onClick={() => setEditingId(s.id)}>
            {t('mcp.row.edit')}
          </button>
          <button type="button" className="text-2xs text-red-600 hover:text-red-800 dark:hover:text-red-300 underline"
            onClick={() => handleDelete(s.id, s.name, isGlobal)}
            disabled={delMut.isPending}>
            {t('mcp.row.delete')}
          </button>
        </div>
      </div>
    );
  };

  const isLoading = globalLoading || userLoading;

  return (
    <div className="h-full overflow-y-auto">
      <div className="max-w-3xl mx-auto px-6 py-8 space-y-8">
        <div>
          <h2 className="text-base font-semibold text-slate-900 mb-1">{t('mcp.title')}</h2>
          <p className="text-[13px] text-slate-500 leading-relaxed">
            {t('mcp.intro')}
          </p>
        </div>

        {isLoading && <div className="text-[13px] text-slate-400">{t('mcp.loading')}</div>}

        {/* Global Servers (admin) */}
        {isAdmin && (globalServers ?? []).length > 0 && (
          <section>
            <div className="flex items-center gap-2 mb-2">
              <h3 className="text-[13px] font-semibold text-slate-900">{t('mcp.globalServers')}</h3>
              <span className="inline-block px-1.5 py-0.5 rounded text-[10px] font-medium bg-slate-100 text-slate-500 leading-none">{t('mcp.sharedAcrossUsers')}</span>
            </div>
            <div>{(globalServers ?? []).map(s => renderServerRow(s, true))}</div>
          </section>
        )}

        {/* Personal Servers */}
        {(userServers ?? []).length > 0 && (
          <section>
            <div className="flex items-center gap-2 mb-2">
              <h3 className="text-[13px] font-semibold text-slate-900">{t('mcp.personalServers')}</h3>
            </div>
            <div>{(userServers ?? []).map(s => renderServerRow(s, false))}</div>
          </section>
        )}

        {/* Empty state */}
        {!isLoading && (globalServers ?? []).length === 0 && (userServers ?? []).length === 0 && (
          <div className="text-[13px] text-slate-400 text-center py-8">
            {t('mcp.empty')}
          </div>
        )}

        {/* Add buttons / forms */}
        <div className="space-y-4">
          {addingSection ? (
            <div>
              <h4 className="text-xs font-semibold text-slate-700 mb-2">
                {addingSection === 'global' ? t('mcp.addGlobalHeading') : t('mcp.addPersonalHeading')}
              </h4>
              <ServerForm
                initial={emptyForm()} isEdit={false}
                sectionLabel={addingSection}
                onSubmit={async (body) => { await saveMut.mutateAsync({ body, isGlobal: addingSection === 'global' }); }}
                onCancel={() => setAddingSection(null)}
                isPending={saveMut.isPending}
              />
            </div>
          ) : (
            <div className="flex gap-2">
              <button type="button" onClick={() => setAddingSection('personal')}
                className="px-3 py-1.5 rounded-md text-xs font-semibold text-accent border border-accent/30 hover:bg-accent-soft transition-colors">
                {t('mcp.addPersonal')}
              </button>
              {isAdmin && (
                <button type="button" onClick={() => setAddingSection('global')}
                  className="px-3 py-1.5 rounded-md text-xs font-semibold text-slate-600 border border-hairline hover:bg-surface transition-colors">
                  {t('mcp.addGlobal')}
                </button>
              )}
            </div>
          )}
        </div>
      </div>
    </div>
  );
}
