"use client";

import { useMemo, useCallback, useEffect } from "react";
import { useSettings } from "@/app/lib/settings";
import {
  runPipeline,
  fetchColumns,
  type PipelineRequest,
  type TableMetadata,
  ApiError,
} from "@/app/lib/api";
import { Badge } from "./ui/badge";
import { Tabs, TabsContent, TabsList, TabsTrigger } from "./ui/tabs";
import { toast } from "sonner";
import { Database, FileText, Settings2, Workflow } from "lucide-react";
import { BuilderTab } from "./pipelines/BuilderTab";
import { JsonTab } from "./pipelines/JsonTab";
import { HistoryTab } from "./pipelines/HistoryTab";
import { usePipelinesStore } from "./pipelines/usePipelinesStore";

type Props = {
  clientName: string | null;
  tables: TableMetadata[];
};

export default function PipelinesPage({ clientName, tables }: Props) {
  const { baseUrl, apiKey } = useSettings();
  const ctx = useMemo(() => ({ baseUrl, apiKey }), [baseUrl, apiKey]);

  const {
    activeTab,
    pipelineName,
    sourceTable,
    sourceColumns,
    sourceLimit,
    conditions,
    condCol,
    condVal,
    groupBy,
    timeGranularity,
    aggColumn,
    aggStrategy,
    sinkTable,
    running,
    lastResult,
    lastError,
    history,
    jsonBody,
    sourceTableColumns,
    columnsLoading,
    setState,
    setConditions,
    addCondition,
    setRunning,
    clearRunResult,
    recordSuccess,
    recordError,
  } = usePipelinesStore();

  useEffect(() => {
    if (!sourceTable || !clientName) {
      setState({ sourceTableColumns: [] });
      return;
    }

    setState({ columnsLoading: true });
    fetchColumns(ctx, sourceTable, clientName)
      .then((cols) => setState({ sourceTableColumns: cols }))
      .catch(() => setState({ sourceTableColumns: [] }))
      .finally(() => setState({ columnsLoading: false }));
  }, [sourceTable, clientName, ctx, setState]);

  const buildRequest = useCallback((): PipelineRequest => {
    const req: PipelineRequest = {};

    if (pipelineName.trim()) {
      req.pipeline = pipelineName.trim();
    }

    if (sourceTable) {
      req.source = {
        table_name: sourceTable,
        columns: sourceColumns.trim()
          ? sourceColumns
              .split(",")
              .map((s) => s.trim())
              .filter(Boolean)
          : undefined,
        conditions: conditions.length > 0 ? conditions : undefined,
        limit: sourceLimit ? parseInt(sourceLimit, 10) : undefined,
      };
    }

    if (groupBy || aggColumn || aggStrategy) {
      req.transform = {
        group_by: groupBy || undefined,
        time_granularity:
          (timeGranularity as "day" | "hour" | "minute") || undefined,
        aggregation_column: aggColumn || undefined,
        aggregation_strategy: aggStrategy || undefined,
      };
    }

    if (sinkTable) {
      req.sink = { table_name: sinkTable };
    }

    return req;
  }, [
    pipelineName,
    sourceTable,
    sourceColumns,
    sourceLimit,
    conditions,
    groupBy,
    timeGranularity,
    aggColumn,
    aggStrategy,
    sinkTable,
  ]);

  const handleRun = async (requestOverride?: PipelineRequest) => {
    if (!clientName) {
      toast.error("No client connected", {
        description: "Select a database client from the sidebar first",
      });
      return;
    }

    setRunning(true);
    clearRunResult();

    const request = requestOverride ?? buildRequest();
    const start = performance.now();

    try {
      const result = await runPipeline(ctx, request, clientName);
      const duration = Math.round(performance.now() - start);
      recordSuccess(request, result, duration);
      toast.success(
        `Pipeline completed - ${result.rows_fetched ?? 0} fetched, ${result.rows_inserted ?? 0} inserted`,
        { duration: 4000 },
      );
    } catch (err) {
      const msg = err instanceof ApiError ? err.message : "Pipeline failed";
      recordError(request, msg, Math.round(performance.now() - start));
      toast.error("Pipeline failed", { description: msg });
    } finally {
      setRunning(false);
    }
  };

  const handleRunJson = async () => {
    try {
      const parsed = JSON.parse(jsonBody);
      await handleRun(parsed);
    } catch {
      toast.error("Invalid JSON");
    }
  };

  return (
    <div className="flex flex-1 flex-col min-h-0">
      <div className="flex items-center gap-3 border-b border-border px-6 py-3">
        <Workflow className="h-4 w-4 text-primary" />
        <h2 className="text-sm font-semibold text-foreground">Pipelines</h2>
        <Badge variant="secondary" className="text-caption">
          {clientName ?? "no client"}
        </Badge>
        <div className="flex-1" />
        <Badge variant="outline" className="text-tiny tabular-nums">
          {history.length} runs
        </Badge>
      </div>

      <Tabs
        value={activeTab}
        onValueChange={(tab) => setState({ activeTab: tab })}
        className="flex flex-col flex-1 min-h-0"
      >
        <div className="border-b border-border px-6">
          <TabsList className="h-8">
            <TabsTrigger value="builder">
              <Settings2 className="mr-1 h-3 w-3" /> Builder
            </TabsTrigger>
            <TabsTrigger value="json">
              <FileText className="mr-1 h-3 w-3" /> JSON
            </TabsTrigger>
            <TabsTrigger value="history">
              <Database className="mr-1 h-3 w-3" /> History
            </TabsTrigger>
          </TabsList>
        </div>

        <TabsContent value="builder" className="flex-1 m-0 overflow-hidden">
          <BuilderTab
            clientName={clientName}
            tables={tables}
            pipelineName={pipelineName}
            setPipelineName={(value) => setState({ pipelineName: value })}
            sourceTable={sourceTable}
            setSourceTable={(value) => setState({ sourceTable: value })}
            sourceColumns={sourceColumns}
            setSourceColumns={(value) => setState({ sourceColumns: value })}
            sourceLimit={sourceLimit}
            setSourceLimit={(value) => setState({ sourceLimit: value })}
            sourceTableColumns={sourceTableColumns}
            columnsLoading={columnsLoading}
            conditions={conditions}
            setConditions={setConditions}
            condCol={condCol}
            setCondCol={(value) => setState({ condCol: value })}
            condVal={condVal}
            setCondVal={(value) => setState({ condVal: value })}
            onAddCondition={addCondition}
            groupBy={groupBy}
            setGroupBy={(value) => setState({ groupBy: value })}
            timeGranularity={timeGranularity}
            setTimeGranularity={(value) => setState({ timeGranularity: value })}
            aggColumn={aggColumn}
            setAggColumn={(value) => setState({ aggColumn: value })}
            aggStrategy={aggStrategy}
            setAggStrategy={(value) => setState({ aggStrategy: value })}
            sinkTable={sinkTable}
            setSinkTable={(value) => setState({ sinkTable: value })}
            running={running}
            onRun={() => handleRun()}
            onViewJson={() => {
              setState({
                jsonBody: JSON.stringify(buildRequest(), null, 2),
                activeTab: "json",
              });
            }}
            lastResult={lastResult}
            lastError={lastError}
          />
        </TabsContent>

        <TabsContent value="json" className="flex-1 m-0 overflow-hidden">
          <JsonTab
            jsonBody={jsonBody}
            setJsonBody={(value) => setState({ jsonBody: value })}
            running={running}
            clientName={clientName}
            onRunJson={handleRunJson}
          />
        </TabsContent>

        <TabsContent value="history" className="flex-1 m-0 overflow-hidden">
          <HistoryTab
            history={history}
            onRerun={(request) => {
              setState({
                jsonBody: JSON.stringify(request, null, 2),
                activeTab: "json",
              });
            }}
          />
        </TabsContent>
      </Tabs>
    </div>
  );
}
