import { useEffect, useState } from "react";
import ReactMarkdown from "react-markdown";

import usageMarkdown from "./usage.md?raw";

import {
  Button,
  Card,
  Dropdown,
  FileUploader,
  InputField,
  InputSection,
  Tabs,
} from "@elvis/ui";

import { OKABE_ITO_COLORS } from "./colors";
import { CLASSIFIERS } from "./classifiers";

import type { CsvSettings, ModelSettings } from "./types";

import { DATASETS } from "./datasets";


interface SidebarProps {
  pointLabel: string;
  setPointLabel: (label: string) => void;
  setCanAddPoints: (canAddPoints: boolean) => void;
  undoDataPoint: () => void;
  clearDataPoints: () => void;
  modelSettings: ModelSettings;
  setModelSettings: (settings: ModelSettings) => void;
  csvSettings: CsvSettings;
  onGetDecisionBoundary: () => void;
  onCsvUpload: (file: File, settings?: CsvSettings) => void;
  onCsvSettingsChange: (settings: CsvSettings) => void;
  csvError: string | null;
  onCsvExport: () => void;
  onSvgExport: () => void;
}

export default function Sidebar({ 
  pointLabel, 
  setPointLabel, 
  setCanAddPoints,
  undoDataPoint,
  clearDataPoints,
  modelSettings, 
  setModelSettings,
  csvSettings,
  onGetDecisionBoundary,
  onCsvUpload,
  onCsvSettingsChange,
  csvError,
  onCsvExport,
  onSvgExport,
}: SidebarProps) {
  const tabs = ["Data", "Model", "Export", "Usage"] as const;
  const [activeTab, setActiveTab] = useState<(typeof tabs)[number]>("Data");

  const presetOptions = DATASETS.map((dataset) => dataset.name) as string[];
  const customDatasetOptions = ["Manual...", "Upload..."] as string[];
  const [datasetOption, setDatasetOption] = useState<string>("Manual...");

  function isPresetOption(option: string) {
    return presetOptions.includes(option);
  }

  function onDatasetOptionChange(option: string) {
    setDatasetOption(option);
    if (isPresetOption(option)) {
      loadPresetDataset(option);
    }
  }

  async function loadPresetDataset(datasetName: string) {
    const dataset = DATASETS.find((d) => d.name === datasetName);
    if (!dataset) {
      return;
    }

    const response = await fetch(dataset.url);
    const blob = await response.blob();
    const file = new File([blob], `${dataset.name}.csv`, { type: "text/csv" });

    const presetCsvSettings = {
      ...csvSettings,
      inputColumns: dataset.inputColumns,
      outputColumn: dataset.outputColumn,
    };

    onCsvUpload(file, presetCsvSettings);
  }

  useEffect(() => {
    clearDataPoints();
    setCanAddPoints(datasetOption === "Manual...");
  }, [datasetOption]);

  return (
    <Card className="bg-white flex flex-col h-full min-w-0 min-h-0 overflow-auto border border-gray-200 rounded p-6 gap-4">
      <Tabs tabs={tabs} activeTab={activeTab} onChange={setActiveTab} />

      { /* Tab content */}
      <div className="flex flex-col gap-8 min-h-0 overflow-auto">
        { activeTab === "Data" && (
          <>
            <InputSection label="Dataset">
              <Dropdown
                label="Input"
                options={customDatasetOptions}
                groupedOptions={[{ label: "Built-in...", options: presetOptions }]}
                activeOption={datasetOption}
                onChange={onDatasetOptionChange}
              />
              { datasetOption === "Manual..." && (
                <>
                  <Dropdown
                    label="Point Label"
                    options={OKABE_ITO_COLORS.map(color => color.name)}
                    activeOption={pointLabel}
                    onChange={(option: string) => setPointLabel(option)}
                  />
                  <div className="grid grid-cols-2 gap-2">
                    <Button
                      label="Undo"
                      onClick={undoDataPoint}
                    />
                    <Button
                      label="Clear"
                      onClick={clearDataPoints}
                    />
                  </div>
                </>
              )}
              { datasetOption === "Upload..." && (
                <FileUploader label="Upload CSV" onFileUpload={onCsvUpload} />
              )}
              { (datasetOption === "Upload..." || isPresetOption(datasetOption)) && (
                <>
                  <div className="grid grid-cols-[minmax(0,2fr)_minmax(0,1fr)] gap-2">
                    <InputField
                      label="Input Columns"
                      value={csvSettings.inputColumns}
                      onChange={(value: string) => {onCsvSettingsChange({ ...csvSettings, inputColumns: value })}}
                    />
                    <InputField
                      label="Output Column"
                      value={csvSettings.outputColumn}
                      onChange={(value: string) => {onCsvSettingsChange({ ...csvSettings, outputColumn: value })}}
                    />
                  </div>
                </>
              )}
            </InputSection>

            { (datasetOption === "Upload..." || isPresetOption(datasetOption)) && (
              <>
                <InputSection label="Preprocessing">
                  <Dropdown
                    label="Normalizer"
                    options={["None", "MinMax", "Standard"]}
                    activeOption={csvSettings.normalizerType}
                    onChange={(option: string) => {onCsvSettingsChange({ ...csvSettings, normalizerType: option })}}
                  />
                  <InputField
                    label="Normal noise standard deviation"
                    value={csvSettings.normalNoiseStd}
                    onChange={(value: string) => {onCsvSettingsChange({ ...csvSettings, normalNoiseStd: value })}}
                  />
                </InputSection>

                <InputSection label="Plotting">
                  <Dropdown
                    label="Projection"
                    options={["Coordinates", "PCA"]}
                    activeOption={csvSettings.projectionType}
                    onChange={(option: string) => {onCsvSettingsChange({ ...csvSettings, projectionType: option })}}
                  />
                  {csvSettings.projectionType === "Coordinates" && (
                    <div className="grid grid-cols-2 gap-2">
                      <InputField
                        label="X1 Column"
                        value={csvSettings.x1Column || ""}
                        onChange={(value: string) => {onCsvSettingsChange({ ...csvSettings, x1Column: value })}}
                      />
                      <InputField
                        label="X2 Column"
                        value={csvSettings.x2Column || ""}
                        onChange={(value: string) => {onCsvSettingsChange({ ...csvSettings, x2Column: value })}}
                      />
                    </div>
                  )}
                </InputSection>

                {csvError && (
                  <InputSection label="Error">
                    <p className="text-red-600 font-semibold">CSV Error: {csvError}</p>
                  </InputSection>
                )}
              </>
            )}
          </>
        )}

        { activeTab === "Model" && (
          <>
            <InputSection label="Classifier Options">
              <Dropdown
                label="Type"
                options={CLASSIFIERS}
                activeOption={modelSettings.type}
                onChange={(option: string) => {
                  setModelSettings({ ...modelSettings, type: option });
                }}
              />
              <InputField
                label="Arguments"
                value={modelSettings.arguments}
                onChange={(value: string) => {
                  setModelSettings({ ...modelSettings, arguments: value });
                }}
              />
            </InputSection>
            <Button
              label="Get Decision Boundary"
              onClick={onGetDecisionBoundary}
            />
          </>
        )}
        { activeTab === "Export" && (
          <div className="flex flex-col gap-4">
            <Button
              label="Dataset as CSV"
              onClick={onCsvExport}
            />
            <Button
              label="Plot as SVG"
              onClick={onSvgExport}
            />
            {/* <Button
              label="Python code"
            /> */}
          </div>
        )}
        { activeTab === "Usage" && (
            <div className="prose leading-loose overflow-auto">
              <ReactMarkdown
                components={{
                  h1: ({ children }) => <h1 className="text-2xl font-bold mt-12 mb-2 first:mt-4">{children}</h1>,
                  h2: ({ children }) => <h2 className="text-xl font-semibold mt-12 mb-2 first:mt-4">{children}</h2>,
                  h3: ({ children }) => <h3 className="text-lg font-semibold mt-12 mb-2 first:mt-4">{children}</h3>,
                  p: ({ children }) => <p className="leading-6 mb-3 last:mb-0">{children}</p>,
                  ul: ({ children }) => <ul className="list-disc pl-5 mb-3">{children}</ul>,
                  ol: ({ children }) => <ol className="list-decimal pl-5 mb-3">{children}</ol>,
                  li: ({ children }) => <li className="mb-1">{children}</li>,
                  code: ({ children }) => <code className="bg-gray-200 px-1 py-0.5 rounded">{children}</code>
                }}
              >
                {usageMarkdown}
              </ReactMarkdown>
            </div>
        )}
      </div>
    </Card>
  )
}
