import * as React from "react";
import Box from "@mui/material/Box";
import Button from "@mui/material/Button";
import TextField from "@mui/material/TextField";
import EditIcon from "@mui/icons-material/Edit";
import Grid from "@mui/material/Unstable_Grid2"; // Grid version 2
import Typography from "@mui/material/Typography";
import Stack from "@mui/material/Stack";
import MenuItem from "@mui/material/MenuItem";
import Select from "@mui/material/Select";
import { useRecoilValue } from "recoil";
import { useSnackbar } from "notistack";
import CircleIcon from "@mui/icons-material/Circle";
import Chip from "@mui/material/Chip";
import SearchIcon from "@mui/icons-material/Search";
import ExpandMoreIcon from "@mui/icons-material/ExpandMore";
// import Collapse from "@mui/material/Collapse";

import {
  createProduct,
  selectProductList,
  retrieveProductList,
  deleteProduct,
} from "@/utils/mysqlCompatible";
import { sessionState } from "@/recoil/atoms";
import { useInitCRUD, useInitForeignKey } from "@/utils/hook";
import type { SQLResult as SQLResultType } from "@/pages/api/sql/run";

import {
  ActionTemplate,
  ResultPreviewTemplate,
  TextFieldWrapper,
  ResultTable,
} from "@/components/Sections/MysqlCompatible/Content/Create";
import CodeBlock, { UnifiedCodeDiffHighlight } from "@/components/CodeBlock";
import CustomCollapse from "@/components/Transform/Collapse";

const SQL_CONTENT = `INSERT INTO products (product_name, price, brand_id)
VALUES (\${product_name}, \${price}, \${brand_id});`;

const SQL_WARNING = `The insert statement will return an error due to the prevented with foreign key constraint.`;
const TABLE_DEFINITION = `CREATE TABLE \`products\` (
  \`product_id\` bigint(20) NOT NULL, 
  \`product_name\` varchar(100) NOT NULL, 
  \`price\` decimal(16, 2) NOT NULL, 
  \`brand_id\` int(11) NOT NULL, 
  PRIMARY KEY (\`product_id\`), 
  CONSTRAINT \`fk_brand_id\` FOREIGN KEY (\`brand_id\`) 
REFERENCES \`brands\` (\`brand_id\`) 
);`;

export default function ForeignKeyContent() {
  const [sql, setSql] = React.useState(SQL_CONTENT);
  const [prodName, setProdName] = React.useState<string | null>("T-Shirt");
  const [prodNameError, setProdNameError] = React.useState<string | null>(null);
  const [price, setPrice] = React.useState<number | null>(100.0);
  const [priceError, setPriceError] = React.useState<string | null>(null);
  const [brandId, setBrandId] = React.useState<number>(0);
  const [result, setResult] = React.useState<SQLResultType | null>(null);
  const [originalResult, setOriginalResult] =
    React.useState<SQLResultType | null>(null);
  const [submitting, setSubmitting] = React.useState(false);
  const [globalLoading, setGlobalLoading] = React.useState(true);
  const [errMsg, setErrMsg] = React.useState<string | null>(null);

  const { enqueueSnackbar } = useSnackbar();

  const session = useRecoilValue(sessionState);
  const [isInitForeignKey, isInitForeignKeyError] = useInitForeignKey(
    !!session
  );

  React.useEffect(() => {
    if (!isInitForeignKeyError) return;
    enqueueSnackbar(
      `Error[init foreign key]: ${isInitForeignKeyError?.message}`,
      {
        variant: "error",
      }
    );
    setGlobalLoading(false);
  }, [isInitForeignKeyError]);

  React.useEffect(() => {
    if (!prodName || !price) {
      return;
    }
    const newSql = SQL_CONTENT.replace(/\${product_name}/g, prodName)
      .replace(/\${price}/g, price.toString())
      .replace(/\${brand_id}/g, brandId.toString());
    setSql(newSql);
  }, [prodName, price, brandId]);

  React.useEffect(() => {
    if (!isInitForeignKey) return;

    const fetchData = async () => {
      try {
        const originalData = await retrieveProductList();
        setOriginalResult(originalData);
      } catch (error: any) {
        console.error(error);
        enqueueSnackbar(`Error[fetch data]: ${error?.message}`, {
          variant: "error",
        });
      } finally {
        setGlobalLoading(false);
      }
    };

    fetchData();
  }, [isInitForeignKey]);

  // React.useEffect(() => {
  //   if (originalResult?.rows && originalResult?.rows?.length > 0) {
  //     setProdId(originalResult.rows[0].productId);
  //   }
  // }, [originalResult]);

  const tableFieldsMemo = React.useMemo(() => {
    // if (result?.fields) {
    //   return result.fields.map((field) => field.name);
    // } else if (originalResult?.fields) {
    //   return originalResult.fields.map((field) => field.name);
    // }
    return ["productName", "price", "brandId"];
  }, [result, originalResult]);

  const tableRowsMemo = React.useMemo(() => {
    const resultRowsIdList =
      result?.rows?.map((i) => i[tableFieldsMemo[0] || "productId"]) || [];
    if (originalResult?.rows && result?.rows) {
      const resultRows = originalResult.rows.map((row) => {
        !resultRowsIdList.includes(row[tableFieldsMemo[0] || "productId"]) &&
          (row._delete = true);
        return row;
      });
      return resultRows;
    } else if (originalResult?.rows) {
      return originalResult.rows;
    }
    return [];
  }, [result, originalResult]);

  const handleEditName = (event: React.ChangeEvent<HTMLInputElement>) => {
    const value = event.target.value.trim();
    if (value.length === 0) {
      setProdNameError("Product name cannot be empty");
      setProdName(null);
    } else {
      setProdNameError(null);
      setProdName(value);
    }
  };

  const handleEditPrice = (event: React.ChangeEvent<HTMLInputElement>) => {
    const value = event.target.value.trim();
    if (value.length === 0) {
      setPriceError("Price cannot be empty");
      setPrice(null);
    } else {
      const price = Number(value);
      if (isNaN(price)) {
        setPriceError("Price must be a number");
        setPrice(null);
      } else if (price <= 0 || price > 1000000) {
        setPriceError("Price must be a positive number");
        setPrice(null);
      } else {
        setPriceError(null);
        setPrice(price);
      }
    }
  };

  const handleSubmmit = async () => {
    if (!prodName || !price) {
      return;
    }
    setSubmitting(true);
    setResult(null);
    setErrMsg(null);
    try {
      const postaData = await createProduct({
        productName: prodName,
        price: price,
        brandId: brandId,
        stock: 1,
      });

      if (postaData.error === true) {
        throw postaData;
      } else {
        setResult(postaData);
      }
    } catch (error: any) {
      console.error(error);
      // enqueueSnackbar(
      //   `Error[run SQL]: ${error?.message} ${error?.sqlMessage}`,
      //   {
      //     variant: "error",
      //   }
      // );
      setErrMsg(`Error[run SQL]: ${error?.message}\n${error?.sqlMessage}`);
    } finally {
      setSubmitting(false);
    }
  };

  return (
    <>
      <ActionTemplate
        inputTitle="Create a new product:"
        sqlContent={sql}
        handleSubmmit={handleSubmmit}
        disableSubbmit={globalLoading || !prodName || !price}
        submitting={globalLoading || submitting}
        submitBtnLabel={
          globalLoading ? "Init sample data" : "Run SQL to check the error"
        }
        result={
          <>
            {errMsg && (
              <Box
                sx={{
                  mb: 2,
                  p: 2,
                  borderRadius: "6px",
                  border: "1px solid #EAEAEA",
                }}
              >
                <Typography
                  component="div"
                  color="error.main"
                  whiteSpace="break-spaces"
                >
                  {errMsg}
                </Typography>
              </Box>
            )}
            <TableDefinition sql={TABLE_DEFINITION} ADDED={[7, 8]} />
          </>
        }
        sqlAlert={{
          status: "warning",
          message:
            "The insert statement will return an error due to the prevented with foreign key constraint.",
        }}
      >
        <TextFieldWrapper title="Product Name">
          <TextField
            id="product-name"
            size="small"
            InputProps={{
              endAdornment: (
                <EditIcon
                  sx={{
                    color: "rgba(168, 177, 193, 0.3)",
                  }}
                />
              ),
            }}
            value={prodName || ""}
            onChange={handleEditName}
            error={!!prodNameError}
            helperText={prodNameError}
          />
        </TextFieldWrapper>
        <TextFieldWrapper title="Price($)">
          <TextField
            id="price"
            size="small"
            InputProps={{
              endAdornment: (
                <EditIcon
                  sx={{
                    color: "rgba(168, 177, 193, 0.3)",
                  }}
                />
              ),
            }}
            value={price || ""}
            onChange={handleEditPrice}
            error={!!priceError}
            helperText={priceError}
          />
        </TextFieldWrapper>
        <TextFieldWrapper title="Brand ID">
          <Select
            size="small"
            id="brand_id"
            value={brandId || 0}
            disabled={globalLoading}
            onChange={(event) => {
              const value = event.target.value;
              setBrandId(value as number);
            }}
            sx={{
              minWidth: "320px",
              color: (theme) => theme.palette.error.main,
            }}
          >
            <MenuItem value={0}>INVALID(brand_id: 0)</MenuItem>
          </Select>
        </TextFieldWrapper>
      </ActionTemplate>

      <ResultPreviewTemplate>
        <ResultTable fields={tableFieldsMemo} rows={tableRowsMemo} />
      </ResultPreviewTemplate>
    </>
  );
}

export function TableDefinition(props: {
  btnLabel?: string;
  sql: string;
  ADDED?: number[];
}) {
  const { btnLabel, sql, ADDED } = props;

  const [expanded, setExpanded] = React.useState(true);

  return (
    <Box>
      <Button
        endIcon={<ExpandMoreIcon />}
        sx={{
          color: (theme) => theme.palette.text.primary,
        }}
        onClick={() => setExpanded(!expanded)}
      >
        {btnLabel || `Check table definition`}
      </Button>
      <CustomCollapse
        in={expanded}
        collapsedSize={40}
        hideButton
        handleChange={() => setExpanded(!expanded)}
      >
        <Box
          sx={{
            border: "1px solid #EAEAEA",
            borderRadius: "6px",
          }}
        >
          <UnifiedCodeDiffHighlight
            language="sql"
            // title="Table Definition"
            text={sql}
            wrapLines
            ADDED={ADDED}
            showLineNumbers
          />
        </Box>
      </CustomCollapse>
    </Box>
  );
}
