import type { Meta, StoryObj } from 'storybook-solidjs-vite';
import { createSignal, onMount, type JSX } from 'solid-js';
import './tasks';
import { argTypesFor, specDescription } from '../stories/docs/element-controls';
import type { TasksCardData } from '../components/tasks-card';
import type { CardEvent } from '../primitives/card-contract';

declare module 'solid-js' {
  // eslint-disable-next-line @typescript-eslint/no-namespace
  namespace JSX {
    interface IntrinsicElements {
      'kc-tasks': JSX.HTMLAttributes<HTMLElement> & {
        heading?: string;
        'card-id'?: string;
        ref?: (el: HTMLElement) => void;
      };
    }
  }
}

type TasksEl = HTMLElement & { data?: TasksCardData; resolution?: Record<string, unknown> };

function Frame(props: { children: JSX.Element }) {
  return <div style={{ 'max-width': '460px' }}>{props.children}</div>;
}

/** Mounts a <kc-tasks>, sets `.data`, logs the emitted CardEvent under the render. */
function TasksDemo(props: { def: TasksCardData; cardId: string; heading?: string }) {
  const [log, setLog] = createSignal<CardEvent[]>([]);
  let el: TasksEl | undefined;
  onMount(() => {
    if (!el) return;
    el.data = props.def;
    el.addEventListener('kc-card', (e) => {
      const detail = (e as CustomEvent<CardEvent>).detail;
      setLog((prev) => [...prev, detail]);
    });
  });
  return (
    <Frame>
      <div style={{ display: 'flex', 'flex-direction': 'column', gap: '12px' }}>
        <kc-tasks ref={(e) => (el = e as TasksEl)} card-id={props.cardId} heading={props.heading} />
        <pre
          style={{
            margin: 0,
            'max-height': '180px',
            overflow: 'auto',
            background: 'var(--color-muted, #f4f4f5)',
            'border-radius': '8px',
            padding: '8px',
            'font-size': '12px',
          }}
        >
          {log().length === 0 ? '// emitted CardEvents appear here' : JSON.stringify(log(), null, 2)}
        </pre>
      </div>
    </Frame>
  );
}

const PLAN: TasksCardData = {
  mode: 'select',
  selectAll: true,
  confirmLabel: 'Run selected',
  tasks: [
    { id: 'lint', label: 'Run linter', checked: true },
    { id: 'test', label: 'Run unit tests', checked: true },
    { id: 'build', label: 'Build production bundle' },
    { id: 'deploy', label: 'Deploy to staging', description: 'Reversible; staging only' },
  ],
};

const REQUIRE_ONE: TasksCardData = {
  confirmLabel: 'Apply',
  allowEmpty: false,
  tasks: [
    { id: 'cache', label: 'Clear the CDN cache' },
    { id: 'reindex', label: 'Rebuild the search index' },
    { id: 'restart', label: 'Restart the workers' },
  ],
};

const BOUNDED: TasksCardData = {
  heading: 'Pick up to 2 reviewers',
  confirmLabel: 'Request review',
  min: 1,
  max: 2,
  tasks: [
    { id: 'ana', label: 'Ana' },
    { id: 'ben', label: 'Ben' },
    { id: 'cat', label: 'Cat' },
    { id: 'dan', label: 'Dan' },
  ],
};

const WITH_DESCRIPTIONS: TasksCardData = {
  selectAll: true,
  confirmLabel: 'Run cleanup',
  tasks: [
    { id: 'tmp', label: 'Delete temp files', description: 'Frees ~2.1 GB; safe to remove' },
    { id: 'logs', label: 'Rotate logs', description: 'Archives logs older than 30 days' },
    { id: 'orphans', label: 'Prune orphaned blobs', description: 'Unreferenced uploads only' },
  ],
};

const HEADING_MAP: Record<string, string | undefined> = {
  'card-plan': 'Approve the plan steps',
  'card-require': 'Choose maintenance steps',
  'card-bounded': undefined,
  'card-desc': 'Storage cleanup',
};

const HTML_SNIPPET = (def: TasksCardData, cardId: string) => {
  const heading = HEADING_MAP[cardId];
  return `<kc-tasks${heading ? ` heading="${heading}"` : ''}></kc-tasks>
<script type="module">
  import '@kitn.ai/chat/elements'; // registers the custom elements

  const el = document.querySelector('kc-tasks');
  // \`data\` is the CardEnvelope.data (set as a property).
  el.data = ${JSON.stringify(def, null, 2)};

  // Toggling rows is local; only CONFIRM emits — a single bubbling \`kc-card\` event.
  el.addEventListener('kc-card', (e) => {
    const ev = e.detail; // { kind:'submit', cardId, data:{ selected } } | ...
    if (ev.kind === 'submit') console.log('selected', ev.data.selected);
  });
</script>`;
};

const meta = {
  title: 'Generative UI/Cards/kc-tasks',
  tags: ['autodocs'],
  argTypes: argTypesFor('kc-tasks'),
  parameters: {
    layout: 'padded',
    docs: {
      description: specDescription('kc-tasks', [
        "`<kc-tasks>` is a **selectable** task/plan list (set via the `data` **property**): checkbox rows + an optional select-all + a confirm button. The user picks a subset, confirms, and the card emits the Card contract's **`submit`** verb up a bubbling **`kc-card`** CustomEvent of `{ kind: 'submit', cardId, data: { selected } }` — the checked ids in **input order**. Toggling rows is local UI state; **only the final confirm emits** (the wire stays quiet, the result atomic).",
        '**Anatomy:** `<kc-card>` chrome (optional heading) → **select-all row** (shown when `selectAll:true` and ≥2 toggleable tasks; indeterminate state when partially checked) → **task rows** (one per `tasks[]` item: checkbox + label + optional description; disabled when `max` reached or `task.disabled`) → **card footer** (selected-count label + confirm `<Button>`, disabled until gating passes; replaced by a read-only resolved summary after submission).',
        '**Gating:** confirm is enabled when `selectedCount >= (min ?? (allowEmpty ? 0 : 1))` and `<= (max ?? ∞)`. Select-all checks every toggleable (non-`disabled`) row and shows an **indeterminate** (`aria-checked="mixed"`) state when only some are checked. When `max` is reached, unchecked rows become non-toggleable. v1 is **select/approve only** (a future `mode:\'progress\'` is reserved in the schema).',
        '**Events** (all frozen Card-contract verbs): `ready` on mount, `submit` on confirm, `error` for a malformed definition (renders the inline `kc-card` error). It **never invents events**. The same shapes flow over the remote iframe transport unchanged.',
      ]),
    },
  },
} satisfies Meta;

export default meta;
type Story = StoryObj;

/** Select a plan (select-all on, a few pre-checked). */
export const SelectAPlan: Story = {
  render: () => <TasksDemo def={PLAN} cardId="card-plan" heading="Approve the plan steps" />,
  parameters: { docs: { source: { code: HTML_SNIPPET(PLAN, 'card-plan'), language: 'html' } } },
};

/** Require at least one (`allowEmpty:false`, the default) — confirm stays disabled until a row is checked. */
export const RequireAtLeastOne: Story = {
  render: () => <TasksDemo def={REQUIRE_ONE} cardId="card-require" heading="Choose maintenance steps" />,
  parameters: { docs: { source: { code: HTML_SNIPPET(REQUIRE_ONE, 'card-require'), language: 'html' } } },
};

/** Bounded (`min`/`max`) — confirm gating + max-reached row disabling. */
export const Bounded: Story = {
  render: () => <TasksDemo def={BOUNDED} cardId="card-bounded" />,
  parameters: { docs: { source: { code: HTML_SNIPPET(BOUNDED, 'card-bounded'), language: 'html' } } },
};

/** Rows with secondary descriptions (linked via aria-describedby). */
export const WithDescriptions: Story = {
  render: () => <TasksDemo def={WITH_DESCRIPTIONS} cardId="card-desc" heading="Storage cleanup" />,
  parameters: { docs: { source: { code: HTML_SNIPPET(WITH_DESCRIPTIONS, 'card-desc'), language: 'html' } } },
};

const RESOLVED_TASKS: TasksCardData = {
  confirmLabel: 'Export',
  tasks: [
    { id: 'sum', label: 'Executive summary' },
    { id: 'data', label: 'Raw data' },
    { id: 'charts', label: 'Charts' },
  ],
};

/** The card after the user confirmed their selection — shows "Selected 2 of 3", no checkboxes or button. */
export const Resolved: Story = {
  name: 'Resolved (read-only)',
  render: () => {
    let el: TasksEl | undefined;
    onMount(() => {
      if (!el) return;
      el.data = RESOLVED_TASKS;
      el.resolution = { kind: 'submit', data: { selected: ['sum', 'charts'] } };
    });
    return (
      <Frame>
        <kc-tasks ref={(e) => (el = e as TasksEl)} card-id="card-resolved-tasks" heading="Export report" />
      </Frame>
    );
  },
  parameters: {
    docs: {
      source: {
        code: `<kc-tasks heading="Export report"></kc-tasks>
<script type="module">
  import '@kitn.ai/chat/elements';
  const el = document.querySelector('kc-tasks');
  el.data = ${JSON.stringify(RESOLVED_TASKS, null, 2)};
  // Setting .resolution renders the chromed read-only view — no checkboxes or confirm button.
  el.resolution = { kind: 'submit', data: { selected: ['sum', 'charts'] } };
</script>`,
        language: 'html',
      },
    },
  },
};

/** A malformed `data` (empty `tasks`) → the inline error state + an `error` event. */
export const ErrorState: Story = {
  render: () => <TasksDemo def={{ tasks: [] } as unknown as TasksCardData} cardId="card-bad" />,
  parameters: {
    docs: {
      source: {
        code: `<kc-tasks></kc-tasks>
<script type="module">
  import '@kitn.ai/chat/elements';
  const el = document.querySelector('kc-tasks');
  // No tasks → inline error state + an \`error\` event.
  el.data = { tasks: [] };
  el.addEventListener('kc-card', (e) => {
    if (e.detail.kind === 'error') console.warn('tasks error:', e.detail.message);
  });
</script>`,
        language: 'html',
      },
    },
  },
};
