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

  type ProjectForm = {
    id?: string;
    guid?: string;
    name: string;
    description: string;
  };

  const PROJECT_PRIMARY_KEY = 'id';

  let selectedProject = $state<ProjectSummary | null>(null);
  let selectedProjectRecordID = $state<string | null>(null);
  let gridTotal = $state<number | null>(null);
  let formOpened = $state(false);
  let formRequest = $state<'insert' | 'update' | 'delete'>('insert');
  let formValues = $state<ProjectForm>({ name: '', description: '' });
  let editorOpened = $state(false);
  let editorValues = $state<{ id?: string; description: string }>({ description: '' });
  let contextRow = $state<Record<string, unknown> | null>(null);
  let refreshKey = $state(0);
  const authToken = GlobalStateStore.getState().session.authToken ?? '';
  const projectOnAPICall = $derived(FormerResolveSpecAPI({
    authToken,
    url: '/api/rs/public/projects'
  }));

  const projectDataSourceOptions = {
    url: '/api/rs',
    authToken: GlobalStateStore.getState().session.authToken,
    schema: 'public',
    entity: 'projects',
    uniqueID: PROJECT_PRIMARY_KEY,
    hotfields: [PROJECT_PRIMARY_KEY, 'guid'],
    computedColumns: [
      {
        name: 'thought_count',
        expression: 'COALESCE((SELECT COUNT(*) FROM public.thoughts t WHERE t.project_id = projects.guid), 0)'
      }
    ],
    sort: [{ column: 'created_at', direction: 'desc' }]
  } as unknown as {
    url: string;
    authToken?: string;
    schema: string;
    entity: string;
    uniqueID: string;
    hotfields: string[];
    computedColumns: { name: string; expression: string }[];
  };

  const columns: GridlerColumn[] = [
    { id: 'name', title: 'Name', dataKey: 'name', width: 260 },
    { id: 'description', title: 'Description', dataKey: 'description', width: 360 },
    { id: 'last_active_at', title: 'Last Active', dataKey: 'last_active_at', width: 200, format: 'datetime' },
    { id: 'created_at', title: 'Created', dataKey: 'created_at', width: 200, format: 'datetime' }
  ];

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

  function toProjectForm(rowData: Record<string, unknown>): ProjectForm {
    return {
      id: String(rowData.id ?? ''),
      guid: String(rowData.guid ?? ''),
      name: String(rowData.name ?? ''),
      description: String(rowData.description ?? '')
    };
  }

  function onProjectRowClick(_row: number, rowData: Record<string, unknown> | undefined) {
    if (!rowData) {
      selectedProject = null;
      selectedProjectRecordID = null;
      return;
    }
    selectedProjectRecordID = String(rowData[PROJECT_PRIMARY_KEY] ?? '');
    const id = String(rowData.guid ?? rowData[PROJECT_PRIMARY_KEY] ?? '');
    selectedProject = {
      id,
      name: String(rowData.name ?? ''),
      description: String(rowData.description ?? ''),
      created_at: String(rowData.created_at ?? ''),
      last_active_at: String(rowData.last_active_at ?? ''),
      thought_count: Number(rowData.thought_count ?? 0)
    };
  }

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

  function onMenuItemSelect(item: GridlerContextMenuItem) {
    if (item.id === 'add') {
      formValues = { name: '', description: '' };
      formRequest = 'insert';
      formOpened = true;
      return;
    }
    if (!contextRow) return;
    if (item.id === 'edit_content') {
      onProjectRowClick(0, contextRow);
      editorValues = {
        id: String(contextRow[PROJECT_PRIMARY_KEY] ?? ''),
        description: String(contextRow.description ?? '')
      };
      editorOpened = true;
      return;
    }
    formValues = toProjectForm(contextRow);
    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 normalizeProjectForm(data: ProjectForm): Record<string, unknown> {
    return {
      name: data.name.trim(),
      description: data.description.trim()
    };
  }

  async function handleProjectSaved() {
    formOpened = false;
    refreshKey += 1;
  }

  async function handleEditorSaved() {
    editorOpened = false;
    if (selectedProjectRecordID && editorValues.id === selectedProjectRecordID && selectedProject) {
      selectedProject.description = editorValues.description;
    }
    refreshKey += 1;
  }
</script>

<div class="space-y-6">
  <div class="flex items-end justify-between">
    <div>
      <h2 class="text-2xl font-semibold text-white">Projects</h2>
      <p class="mt-1 text-sm text-slate-400">
        {#if gridTotal === null}
          Server-backed grid
        {:else}
          {gridTotal} project{gridTotal !== 1 ? 's' : ''}
        {/if}
      </p>
    </div>
    <div class="flex gap-2">
      <button
        class="inline-flex items-center 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: '' };
          formRequest = 'insert';
          formOpened = true;
        }}
      >New project</button>
    </div>
  </div>

  <div class="rounded-2xl border border-white/10 bg-slate-950/30 p-3">
    {#key refreshKey}
      <ErrorBoundary namespace="ProjectsGridlerFull">
        <GridlerFull
          {columns}
          theme={adminGridTheme}
          rowMarkers="number"
          height={420}
          dataSource="resolvespec"
          dataSourceOptions={projectDataSourceOptions}
          serverSideSearch={true}
          searchColumns={['name', 'description']}
          {menuItems}
          onRowClick={onProjectRowClick}
          onGridEvent={(type, _item, _column, _coords, detail) => {
            if (type !== 'page_loaded' && type !== 'load') return;
            const total = detail?.total;
            if (typeof total === 'number') gridTotal = total;
          }}
          {onRowDblClick}
          {onRowContextMenu}
          {onMenuItemSelect}
        />
      </ErrorBoundary>
    {/key}
  </div>
  {#if selectedProject}
      <div class="rounded-2xl border border-white/10 bg-slate-900/70 p-4">
        <div class="flex items-center justify-between gap-3">
          <h3 class="text-sm font-semibold text-white">Selected project</h3>
          <button
            class="text-xs text-cyan-300 hover:text-cyan-200"
            onclick={() => {
              const project = selectedProject;
              if (!project) return;
              editorValues = {
                id: selectedProjectRecordID ?? undefined,
                description: project.description
              };
              editorOpened = true;
            }}
          >Edit Content</button>
        </div>
        <p class="mt-2 text-sm text-slate-300"><strong class="text-slate-100">{selectedProject.name}</strong> · {selectedProject.thought_count} thoughts</p>
        <p class="mt-1 text-sm text-slate-400">{selectedProject.description || 'No description.'}</p>
      </div>
  {/if}
</div>

<ErrorBoundary namespace="ProjectsEditorFormer">
  <FormerShell
    bind:opened={editorOpened}
    bind:values={editorValues}
    request="update"
    title="Edit Project Description"
    uniqueKeyField={PROJECT_PRIMARY_KEY}
    width="min(96vw, 90rem)"
    onAPICall={projectOnAPICall}
    beforeSave={(data) => ({ description: data.description.trim() })}
    afterSave={handleEditorSaved}
    onClose={() => {
      editorOpened = false;
    }}
  >
    {#snippet children(state)}
      <ContentEditorField
        filename="project.md"
        value={state.values?.description ?? ''}
        onchange={(v) => state.setState('values', { ...state.values, description: v })}
      />
    {/snippet}
  </FormerShell>
</ErrorBoundary>

<ErrorBoundary namespace="ProjectsFormer">
  <FormerShell
    bind:opened={formOpened}
    bind:values={formValues}
    bind:request={formRequest}
    title={formRequest === 'insert' ? 'New Project' : formRequest === 'update' ? 'Edit Project' : 'Delete Project'}
    uniqueKeyField={PROJECT_PRIMARY_KEY}
    onAPICall={projectOnAPICall}
    beforeSave={normalizeProjectForm}
    afterSave={handleProjectSaved}
    onClose={() => {
      formOpened = false;
    }}
  >
    {#snippet children(state)}
      <TextInputCtrl
        label="Project name"
        name="name"
        required
        disabled={state.request === 'delete'}
        value={state.values?.name ?? ''}
        onchange={(v) => state.setState('values', { ...state.values, name: v })}
      />
      <ContentEditorField
        filename="project.md"
        value={state.values?.description ?? ''}
        disabled={state.request === 'delete'}
        onchange={(v) => state.setState('values', { ...state.values, description: v })}
      />
    {/snippet}
  </FormerShell>
</ErrorBoundary>
