'use client';

import { useState, useCallback, useMemo } from 'react';
import type { QueryResult } from '@/app/lib/types';
import { tokenizeLine, TOKEN_CLASSES } from '@/app/lib/sql-highlight';
import { queryRunner } from '@/app/lib/query-runner';
import { buildSankeyFromResults } from '@/app/lib/sankey/builders';
import { useT } from './ContentProvider';
import { useCustomer } from './CustomerProvider';
import { QueryResultTable } from './QueryResultTable';
import { SankeyDiagram } from './SankeyDiagram';
import { DbIcon, PlayIcon, SpinnerIcon } from './icons';
import { CopyButton } from './CopyButton';
import { Badge, cx, Frame, FrameHeader } from './ui';

/**
 * A SQL statement written by the model. It is NEVER run automatically: the user reads it and presses Run, which
 * is the permission. (A result the user already approved this session is shown again without asking, since
 * showing it contacts no one.)
 */
export function SqlBlock({ code }: { code: string }) {
  const t = useT();
  const customerId = useCustomer()?.id; // a query on a customer's positions must be limited to them, so it is run as them
  const [cached]                      = useState(() => queryRunner.peek(code, customerId));
  const [queryState, setQueryState]   = useState<'idle' | 'running' | 'done'>(cached ? 'done' : 'idle');
  const [result, setResult]           = useState<QueryResult | null>(cached ?? null);
  const lines                         = code.split('\n');

  const runQuery = useCallback(async () => {
    if (queryState === 'running') return;
    setQueryState('running');
    setResult(null);
    try {
      // `force`: pressing Run always asks the database, and replaces any remembered result.
      setResult(await queryRunner.run(code, { force: true, customerId }));
    } finally {
      setQueryState('done');
    }
  }, [code, queryState, customerId]);

  // Stable between renders, so the diagram below doesn't recompute its layout every time this component updates.
  const chartData = useMemo(
    () => (result && !result.error && result.rows.length >= 2 ? buildSankeyFromResults(result) : null),
    [result],
  );

  return (
    <div className="my-5">
      <Frame flush>
        {/* Header */}
        <FrameHeader>
          <div className="flex items-center gap-2.5">
            {/* macOS dots */}
            <div className="flex gap-[5px]">
              <span className="block size-2.5 rounded-[50%] bg-dot-red" />
              <span className="block size-2.5 rounded-[50%] bg-dot-yellow" />
              <span className="block size-2.5 rounded-[50%] bg-dot-green" />
            </div>
            <Badge tone="violet" icon={<DbIcon size={11} color="var(--color-violet)" strokeWidth={1.8} />}>SQL</Badge>
          </div>
          <div className="flex items-center gap-1.5">
            {/* Run button */}
            <button
              onClick={runQuery}
              disabled={queryState === 'running'}
              className={cx('flex items-center gap-[5px] rounded-[7px] border border-success/40 bg-success/8 px-2.5 py-[5px] text-[13px] text-success transition-all', queryState === 'running' ? 'cursor-not-allowed opacity-50' : 'cursor-pointer opacity-100')}
            >
              {queryState === 'running' ? (
                <>
                  <SpinnerIcon size={12} />
                  {t('sql.running')}
                </>
              ) : (
                <>
                  <PlayIcon />
                  {t('sql.run')}
                </>
              )}
            </button>
            <CopyButton text={code} />
          </div>
        </FrameHeader>
        {/* Code body */}
        <div className="overflow-x-auto bg-panel-code">
          <table className="w-full border-collapse text-[15px]">
            <tbody>
              {lines.map((line, i) => (
                <tr key={i} className="transition-[background] duration-100 hover:bg-accent/4">
                  <td className="w-10 border-r border-line-soft py-0.5 pr-3.5 pl-4 text-right font-code text-[13px] text-subtle select-none">
                    {i + 1}
                  </td>
                  <td className="px-4 py-0.5 font-code leading-[1.7] whitespace-pre">
                    {tokenizeLine(line).map((tok, j) => (
                      <span key={j} className={TOKEN_CLASSES[tok.type]}>{tok.text}</span>
                    ))}
                  </td>
                </tr>
              ))}
            </tbody>
          </table>
          <div className="h-2.5" />
        </div>
      </Frame>

      {/* Waiting for the user's approval */}
      {queryState === 'idle' && (
        <div className="mt-2.5 flex items-center justify-between gap-3 rounded-[10px] border border-warning/25 bg-warning/10 px-3.5 py-2.5 text-[14px] text-warning-ink">
          <span>{t('sql.notRun')}</span>
          <button
            onClick={runQuery}
            className="flex shrink-0 cursor-pointer items-center gap-[5px] rounded-[7px] border border-success/40 bg-success/8 px-2.5 py-[5px] text-[13px] text-success transition-all"
          >
            <PlayIcon />
            {t('sql.runQuery')}
          </button>
        </div>
      )}

      {/* Running indicator */}
      {queryState === 'running' && (
        <div className="mt-2.5 flex items-center gap-2 rounded-[10px] border border-edge bg-notice px-3.5 py-2.5 text-[14px] text-muted">
          <SpinnerIcon size={13} color="var(--color-success)" />
          {t('sql.executing')}
        </div>
      )}
      {result && queryState === 'done' && <QueryResultTable result={result} />}
      {queryState === 'done' && chartData && (
        <div className="mt-2">
          <SankeyDiagram data={chartData} />
        </div>
      )}
    </div>
  );
}
