<script lang="ts">
  import {
    ErrorBoundary,
    FormerResolveSpecAPI,
    GridlerFull,
    NativeSelectCtrl,
    TextInputCtrl,
    type GridlerColumn,
    type GridlerContextMenuItem,
  } from "@warkypublic/svelix";
  import { adminGridTheme } from "../../gridTheme";
  import { GlobalStateStore } from "../../shellState";
  import type { AgentGuardrail } from "../../types";
  import FormerShell from "../shared/FormerShell.svelte";
  import ContentEditorField from "../shared/ContentEditorField.svelte";

  type GuardrailForm = {
    id?: string;
    name: string;
    description: string;
    content: string;
    severity: string;
    tags: string;
  };

  const GUARDRAIL_PRIMARY_KEY = 'id';

  const severityClasses: Record<string, string> = {
    low: 'bg-emerald-400/10 text-emerald-200',
    medium: 'bg-amber-400/10 text-amber-200',
    high: 'bg-orange-400/10 text-orange-200',
    critical: 'bg-rose-400/10 text-rose-200'
  };

  let selectedGuardrail = $state<AgentGuardrail | null>(null);
  let gridTotal = $state<number | null>(null);
  let formOpened = $state(false);
  let formRequest = $state<'insert' | 'update' | 'delete'>('insert');
  let formValues = $state<GuardrailForm>({
    name: '',
    description: '',
    content: '',
    severity: 'medium',
    tags: ''
  });
  let editorOpened = $state(false);
  let editorValues = $state<{ id?: string; content: string }>({ content: '' });
  let contextRow = $state<Record<string, unknown> | null>(null);
  let refreshKey = $state(0);
  const authToken = GlobalStateStore.getState().session.authToken ?? '';
  const guardrailOnAPICall = $derived(FormerResolveSpecAPI({
    authToken,
    url: '/api/rs/public/agent_guardrails'
  }));

  const columns: GridlerColumn[] = [
    { id: 'name', title: 'Name', dataKey: 'name', width: 240 },
    { id: 'description', title: 'Description', dataKey: 'description', width: 320 },
    { id: 'severity', title: 'Severity', dataKey: 'severity', width: 120 },
    { id: 'tags', title: 'Tags', dataKey: 'tags', width: 220 },
    { id: 'created_at', title: 'Created', dataKey: 'created_at', width: 180, format: 'datetime' },
    { id: 'updated_at', title: 'Updated', dataKey: 'updated_at', width: 180, format: 'datetime' }
  ];

  const menuItems: GridlerContextMenuItem[] = [
    { id: 'add', label: 'Add' },
    { id: 'edit', label: 'Edit' },
    { id: 'edit_content', label: 'Edit Content' },
    { id: 'delete', label: 'Delete' }
  ];

  const guardrailsDataSourceOptions = {
    url: '/api/rs',
    authToken: GlobalStateStore.getState().session.authToken,
    schema: 'public',
    entity: 'agent_guardrails',
    uniqueID: GUARDRAIL_PRIMARY_KEY,
    hotfields: [GUARDRAIL_PRIMARY_KEY],
    sort: [{ column: 'created_at', direction: 'desc' }]
  } as unknown as {
    url: string;
    authToken?: string;
    schema: string;
    entity: string;
    uniqueID: string;
    hotfields: string[];
  };

  function normalizeTags(value: unknown): string[] {
    if (Array.isArray(value)) return value.map((tag) => String(tag).trim()).filter(Boolean);
    if (typeof value !== 'string' || !value.trim()) return [];
    const trimmed = value.trim();
    if (trimmed.startsWith('{') && trimmed.endsWith('}')) {
      return trimmed
        .slice(1, -1)
        .split(',')
        .map((tag) => tag.trim().replace(/^"(.*)"$/, '$1'))
        .filter(Boolean);
    }
    return trimmed.split(',').map((tag) => tag.trim()).filter(Boolean);
  }

  function normalizeGuardrail(rowData: Record<string, unknown>): AgentGuardrail {
    return {
      id: String(rowData.id ?? ''),
      name: String(rowData.name ?? ''),
      description: String(rowData.description ?? ''),
      content: String(rowData.content ?? ''),
      severity: (typeof rowData.severity === 'string' ? rowData.severity : 'medium') as AgentGuardrail['severity'],
      tags: normalizeTags(rowData.tags),
      created_at: String(rowData.created_at ?? ''),
      updated_at: String(rowData.updated_at ?? '')
    };
  }

  function toGuardrailForm(guardrail: AgentGuardrail): GuardrailForm {
    return {
      id: guardrail.id,
      name: guardrail.name,
      description: guardrail.description,
      content: guardrail.content,
      severity: guardrail.severity,
      tags: guardrail.tags.join(', ')
    };
  }

  function normalizeGuardrailRecordForFormer(data: Record<string, unknown>): GuardrailForm {
    return {
      id: data.id != null ? String(data.id) : undefined,
      name: typeof data.name === 'string' ? data.name : '',
      description: typeof data.description === 'string' ? data.description : '',
      content: typeof data.content === 'string' ? data.content : '',
      severity: typeof data.severity === 'string' ? data.severity : 'medium',
      tags: normalizeTags(data.tags).join(', ')
    };
  }

  async function loadGuardrailFromRow(rowData: Record<string, unknown>): Promise<AgentGuardrail> {
    const id = String(rowData[GUARDRAIL_PRIMARY_KEY] ?? '');
    return await guardrailOnAPICall('read', 'update', undefined, id) as AgentGuardrail;
  }

  function onRowClick(_row: number, rowData: Record<string, unknown> | undefined) {
    selectedGuardrail = rowData ? normalizeGuardrail(rowData) : null;
  }

  function onRowContextMenu(_row: number, rowData: Record<string, unknown> | undefined) {
    contextRow = rowData ?? null;
  }

  async function onMenuItemSelect(item: GridlerContextMenuItem) {
    if (item.id === 'add') {
      formValues = { name: '', description: '', content: '', severity: 'medium', tags: '' };
      formRequest = 'insert';
      formOpened = true;
      return;
    }
    if (!contextRow) return;
    if (item.id === 'edit_content') {
      const guardrail = normalizeGuardrail(contextRow);
      selectedGuardrail = guardrail;
      editorValues = { id: guardrail.id, content: guardrail.content };
      editorOpened = true;
      return;
    }
    const guardrail = normalizeGuardrail(contextRow);
    formValues = toGuardrailForm(guardrail);
    formRequest = item.id === 'delete' ? 'delete' : 'update';
    formOpened = true;
  }

  function onRowDblClick(_row: number, rowData: Record<string, unknown> | undefined) {
    if (!rowData) return;
    contextRow = rowData;
    void onMenuItemSelect({ id: 'edit', label: 'Edit' });
  }

  function onGridEvent(
    type: string,
    _item?: unknown,
    _column?: unknown,
    _coords?: unknown,
    detail?: Record<string, unknown>
  ) {
    if (type !== 'page_loaded' && type !== 'load') return;
    const total = detail?.total;
    if (typeof total === 'number') gridTotal = total;
  }

  function normalizeGuardrailForm(data: GuardrailForm): Record<string, unknown> {
    return {
      name: data.name.trim(),
      description: data.description.trim(),
      content: data.content,
      severity: data.severity,
      tags: data.tags.split(',').map((tag) => tag.trim()).filter(Boolean)
    };
  }

  async function handleGuardrailSaved() {
    formOpened = false;
    if (contextRow?.id) {
      selectedGuardrail = await loadGuardrailFromRow(contextRow);
    }
    refreshKey += 1;
  }

  async function handleGuardrailEditorSaved() {
    editorOpened = false;
    if (editorValues.id) {
      selectedGuardrail = await guardrailOnAPICall('read', 'update', undefined, editorValues.id) as AgentGuardrail;
      editorValues = { id: selectedGuardrail.id, content: selectedGuardrail.content };
    }
    refreshKey += 1;
  }

  function formatDate(value?: string): string {
    if (!value) return '—';
    return new Date(value).toLocaleString();
  }
</script>

<div class="space-y-4 w-full">
  <div class="flex flex-col gap-3 sm:flex-row sm:items-end sm:justify-between">
    <div>
      <h2 class="text-2xl font-semibold text-white">Guardrails</h2>
      <p class="mt-1 text-sm text-slate-400">
        {#if gridTotal === null}
          Server-backed grid
        {:else}
          {gridTotal} guardrail{gridTotal !== 1 ? 's' : ''}
        {/if}
      </p>
    </div>
    <div class="flex items-center gap-3">
      <button
        class="rounded-xl border border-white/10 bg-white/5 px-4 py-2 text-sm text-slate-200 transition hover:bg-white/10"
        onclick={() => {
          formValues = { name: '', description: '', content: '', severity: 'medium', tags: '' };
          formRequest = 'insert';
          formOpened = true;
        }}
      >New Guardrail</button>
    </div>
  </div>

  <div class="flex flex-col gap-4">
    <div class="rounded-2xl border border-white/10 bg-slate-950/30 p-3">
      {#key refreshKey}
        <ErrorBoundary namespace="GuardrailsGridlerFull">
          <GridlerFull
            {columns}
            theme={adminGridTheme}
            rowMarkers="number"
            height={560}
            width="100%"
            pageSize={40}
            dataSource="resolvespec"
            dataSourceOptions={guardrailsDataSourceOptions}
            serverSideSearch={true}
            searchColumns={['name', 'description', 'content', 'severity', 'tags']}
            {menuItems}
            {onGridEvent}
            {onRowClick}
            {onRowDblClick}
            {onRowContextMenu}
            {onMenuItemSelect}
          />
        </ErrorBoundary>
      {/key}
    </div>

    <aside class="rounded-2xl border border-white/10 bg-slate-900/70 p-4">
      <div class="flex items-center justify-between">
        <h3 class="text-sm font-semibold text-white">Guardrail Inspector</h3>
        {#if selectedGuardrail}
          <button
            class="text-xs text-cyan-300 hover:text-cyan-200"
            onclick={() => {
              const guardrail = selectedGuardrail;
              if (!guardrail) return;
              editorValues = { id: guardrail.id, content: guardrail.content };
              editorOpened = true;
            }}
          >Edit Content</button>
        {/if}
      </div>

      {#if !selectedGuardrail}
        <p class="mt-3 text-sm text-slate-500">Select a guardrail row to inspect its rule content.</p>
      {:else}
        <div class="mt-3 space-y-3 text-sm text-slate-300">
          <div class="flex flex-wrap items-center gap-2">
            <p class="text-base font-semibold text-slate-100">{selectedGuardrail.name}</p>
            <span class={`inline-flex items-center rounded-lg px-2.5 py-0.5 text-xs font-medium ${severityClasses[selectedGuardrail.severity] ?? severityClasses.medium}`}>
              {selectedGuardrail.severity}
            </span>
          </div>

          <div class="rounded-xl border border-white/10 bg-white/5 p-3 space-y-1">
            <p><strong class="text-slate-100">Description:</strong> {selectedGuardrail.description || '—'}</p>
            <p><strong class="text-slate-100">Created:</strong> {formatDate(selectedGuardrail.created_at)}</p>
            <p><strong class="text-slate-100">Updated:</strong> {formatDate(selectedGuardrail.updated_at)}</p>
          </div>

          <div class="rounded-xl border border-white/10 bg-white/5 p-3">
            <p class="text-xs uppercase tracking-[0.18em] text-slate-500">Content</p>
            <p class="mt-2 whitespace-pre-wrap text-slate-300">{selectedGuardrail.content}</p>
          </div>

          <div class="rounded-xl border border-white/10 bg-white/5 p-3">
            <p class="text-xs uppercase tracking-[0.18em] text-slate-500">Tags</p>
            <div class="mt-2 flex flex-wrap gap-1.5">
              {#if selectedGuardrail.tags.length}
                {#each selectedGuardrail.tags as tag}
                  <span class="rounded-md bg-white/10 px-2 py-0.5 text-xs text-slate-300">{tag}</span>
                {/each}
              {:else}
                <span class="text-slate-500">No tags</span>
              {/if}
            </div>
          </div>
        </div>
      {/if}
    </aside>
  </div>
</div>

<ErrorBoundary namespace="GuardrailsEditorFormer">
  <FormerShell
    bind:opened={editorOpened}
    bind:values={editorValues}
    request="update"
    title="Edit Guardrail Content"
    uniqueKeyField={GUARDRAIL_PRIMARY_KEY}
    width="min(96vw, 90rem)"
    onAPICall={guardrailOnAPICall}
    beforeSave={(data) => ({ content: data.content })}
    afterSave={handleGuardrailEditorSaved}
    onClose={() => { editorOpened = false; }}
  >
    {#snippet children(state)}
      <ContentEditorField
        filename="guardrail.md"
        value={state.values?.content ?? ''}
        onchange={(v) => state.setState('values', { ...state.values, content: v })}
      />
    {/snippet}
  </FormerShell>
</ErrorBoundary>

<ErrorBoundary namespace="GuardrailsFormer">
  <FormerShell
    bind:opened={formOpened}
    bind:values={formValues}
    bind:request={formRequest}
    title={formRequest === 'insert' ? 'New Guardrail' : formRequest === 'update' ? 'Edit Guardrail' : 'Delete Guardrail'}
    uniqueKeyField={GUARDRAIL_PRIMARY_KEY}
    onAPICall={guardrailOnAPICall}
    afterGet={async (data) => normalizeGuardrailRecordForFormer(data as Record<string, unknown>)}
    beforeSave={normalizeGuardrailForm}
    afterSave={handleGuardrailSaved}
    onClose={() => { formOpened = false; }}
  >
    {#snippet children(state)}
      <div class="space-y-4 p-4">
        <TextInputCtrl
          label="Name"
          name="name"
          required
          disabled={state.request === 'delete'}
          value={state.values?.name ?? ''}
          onchange={(v) => state.setState('values', { ...state.values, name: v })}
        />
        <TextInputCtrl
          label="Description"
          name="description"
          disabled={state.request === 'delete'}
          value={state.values?.description ?? ''}
          onchange={(v) => state.setState('values', { ...state.values, description: v })}
        />
        <ContentEditorField
          filename="guardrail.md"
          value={state.values?.content ?? ''}
          disabled={state.request === 'delete'}
          onchange={(v) => state.setState('values', { ...state.values, content: v })}
        />
        <NativeSelectCtrl
          label="Severity"
          name="severity"
          disabled={state.request === 'delete'}
          value={state.values?.severity ?? 'medium'}
          options={['low', 'medium', 'high', 'critical']}
          onchange={(v) => state.setState('values', { ...state.values, severity: v })}
        />
        <TextInputCtrl
          label="Tags"
          name="tags"
          placeholder="comma-separated"
          disabled={state.request === 'delete'}
          value={state.values?.tags ?? ''}
          onchange={(v) => state.setState('values', { ...state.values, tags: v })}
        />
      </div>
    {/snippet}
  </FormerShell>
</ErrorBoundary>
