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

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

  const SKILL_PRIMARY_KEY = 'id';

  let selectedSkill = $state<AgentSkill | null>(null);
  let gridTotal = $state<number | null>(null);
  let formOpened = $state(false);
  let formRequest = $state<'insert' | 'update' | 'delete'>('insert');
  let formValues = $state<SkillForm>({
    name: '',
    description: '',
    content: '',
    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 skillOnAPICall = $derived(FormerResolveSpecAPI({
    authToken,
    url: '/api/rs/public/agent_skills'
  }));

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

  const columns: GridlerColumn[] = [
    { id: 'name', title: 'Name', dataKey: 'name', width: 240 },
    { id: 'description', title: 'Description', dataKey: 'description', width: 300 },
    { 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' }
  ];

  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 normalizeSkill(rowData: Record<string, unknown>): AgentSkill {
    return {
      id: String(rowData.id ?? ''),
      name: String(rowData.name ?? ''),
      description: String(rowData.description ?? ''),
      content: String(rowData.content ?? ''),
      tags: normalizeTags(rowData.tags),
      created_at: String(rowData.created_at ?? ''),
      updated_at: String(rowData.updated_at ?? '')
    };
  }

  function toSkillForm(skill: AgentSkill): SkillForm {
    return {
      id: skill.id,
      name: skill.name,
      description: skill.description,
      content: skill.content,
      tags: skill.tags.join(', ')
    };
  }

  function normalizeSkillRecordForFormer(data: Record<string, unknown>): SkillForm {
    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 : '',
      tags: normalizeTags(data.tags).join(', ')
    };
  }

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

  async function loadSkillFromRow(rowData: Record<string, unknown>): Promise<AgentSkill> {
    const id = String(rowData[SKILL_PRIMARY_KEY] ?? '');
    const data = await skillOnAPICall('read', 'update', undefined, id) as Record<string, unknown>;
    return normalizeSkill(data);
  }

  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: '', tags: '' };
      formRequest = 'insert';
      formOpened = true;
      return;
    }
    if (!contextRow) return;
    if (item.id === 'edit_content') {
      const skill = normalizeSkill(contextRow);
      selectedSkill = skill;
      editorValues = { id: skill.id, content: skill.content };
      editorOpened = true;
      return;
    }
    const skill = normalizeSkill(contextRow);
    formValues = toSkillForm(skill);
    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 normalizeSkillForm(data: SkillForm): Record<string, unknown> {
    return {
      name: data.name.trim(),
      description: data.description.trim(),
      content: data.content,
      tags: data.tags.split(',').map((tag) => tag.trim()).filter(Boolean)
    };
  }

  async function handleSkillSaved() {
    formOpened = false;
    if (contextRow?.[SKILL_PRIMARY_KEY]) {
      const data = await skillOnAPICall('read', 'update', undefined, String(contextRow[SKILL_PRIMARY_KEY])) as Record<string, unknown>;
      selectedSkill = normalizeSkill(data);
    }
    refreshKey += 1;
  }

  async function handleEditorSaved() {
    editorOpened = false;
    if (editorValues.id) {
      const data = await skillOnAPICall('read', 'update', undefined, String(editorValues.id)) as Record<string, unknown>;
      const refreshed = normalizeSkill(data);
      selectedSkill = refreshed;
      editorValues = { id: refreshed.id, content: refreshed.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">Skills</h2>
      <p class="mt-1 text-sm text-slate-400">
        {#if gridTotal === null}
          Server-backed grid
        {:else}
          {gridTotal} skill{gridTotal !== 1 ? 's' : ''}
        {/if}
      </p>
    </div>
    <div class="flex items-center gap-3">
      <button
        class="rounded-xl border border-cyan-300/30 bg-cyan-400/10 px-4 py-2 text-sm font-medium text-cyan-100 transition hover:bg-cyan-400/20"
        onclick={() => {
          formValues = { name: '', description: '', content: '', tags: '' };
          formRequest = 'insert';
          formOpened = true;
        }}
      >New Skill</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="SkillsGridlerFull">
          <GridlerFull
            {columns}
            theme={adminGridTheme}
            rowMarkers="number"
            height={420}
            width="100%"
            pageSize={40}
            dataSource="resolvespec"
            dataSourceOptions={skillsDataSourceOptions}
            serverSideSearch={true}
            searchColumns={['name', 'description', 'content', '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-start justify-between gap-3">
          <h3 class="text-sm font-semibold text-white">Skill Inspector</h3>
          {#if selectedSkill}
            <button
              class="text-xs text-cyan-300 hover:text-cyan-200"
              onclick={() => {
                if (!selectedSkill) return;
                editorValues = { id: selectedSkill.id, content: selectedSkill.content };
                editorOpened = true;
              }}
            >Edit Content</button>
          {/if}
        </div>

        {#if !selectedSkill}
          <p class="mt-3 text-sm text-slate-500">
            Select a skill row to inspect details.
          </p>
        {:else}
          <div class="mt-3 space-y-3 text-sm text-slate-300">
            <p class="text-base font-semibold text-slate-100">{selectedSkill.name}</p>
            <p><strong class="text-slate-100">Description:</strong> {selectedSkill.description || '—'}</p>
            <p><strong class="text-slate-100">Created:</strong> {formatDate(selectedSkill.created_at)}</p>
            <p><strong class="text-slate-100">Updated:</strong> {formatDate(selectedSkill.updated_at)}</p>

            <div>
              <p class="text-xs uppercase tracking-[0.18em] text-slate-500">Tags</p>
              <div class="mt-2 flex flex-wrap gap-2">
                {#if selectedSkill.tags.length}
                  {#each selectedSkill.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>
              <p class="text-xs uppercase tracking-[0.18em] text-slate-500">Content</p>
              <pre class="mt-2 overflow-x-auto rounded-xl bg-slate-950/60 p-3 text-xs text-slate-300 whitespace-pre-wrap">{selectedSkill.content}</pre>
            </div>
          </div>
        {/if}
    </aside>
  </div>
</div>

<ErrorBoundary namespace="SkillsEditorFormer">
  <FormerShell
    bind:opened={editorOpened}
    bind:values={editorValues}
    request="update"
    title="Edit Skill Content"
    uniqueKeyField={SKILL_PRIMARY_KEY}
    width="min(96vw, 90rem)"
    onAPICall={skillOnAPICall}
    beforeSave={(data) => ({ content: data.content })}
    afterSave={handleEditorSaved}
    onClose={() => {
      editorOpened = false;
    }}
  >
    {#snippet children(state)}
      <ContentEditorField
        filename="skill.md"
        value={state.values?.content ?? ''}
        disabled={state.request === 'delete'}
        onchange={(v) => state.setState('values', { ...state.values, content: v })}
      />
    {/snippet}
  </FormerShell>
</ErrorBoundary>

<ErrorBoundary namespace="SkillsFormer">
  <FormerShell
    bind:opened={formOpened}
    bind:values={formValues}
    bind:request={formRequest}
    title={formRequest === 'insert' ? 'New Skill' : formRequest === 'update' ? 'Edit Skill' : 'Delete Skill'}
    uniqueKeyField={SKILL_PRIMARY_KEY}
    onAPICall={skillOnAPICall}
    afterGet={async (data) => normalizeSkillRecordForFormer(data as Record<string, unknown>)}
    beforeSave={normalizeSkillForm}
    afterSave={handleSkillSaved}
    onClose={() => {
      formOpened = false;
    }}
  >
    {#snippet children(state)}
      <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 })}
      />
      <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 })}
      />
      <ContentEditorField
        filename="skill.md"
        value={state.values?.content ?? ''}
        onchange={(v) => state.setState('values', { ...state.values, content: v })}
      />
    {/snippet}
  </FormerShell>
</ErrorBoundary>
