import * as React from "react";
import Box from "@mui/material/Box";
import Button from "@mui/material/Button";
import Container from "@mui/material/Container";
import Stack from "@mui/material/Stack";
import Slider, {
  SliderThumb,
  SliderValueLabelProps,
} from "@mui/material/Slider";
import Typography from "@mui/material/Typography";
import { styled } from "@mui/material/styles";
import Grid from "@mui/material/Unstable_Grid2";
import ReactEcharts from "echarts-for-react";
import CircularProgress from "@mui/material/CircularProgress";
import WatchLaterIcon from "@mui/icons-material/WatchLater";
import TextField from "@mui/material/TextField";
import LockIcon from "@mui/icons-material/Lock";
import RotateRightIcon from "@mui/icons-material/RotateRight";
import InfoOutlinedIcon from "@mui/icons-material/InfoOutlined";
import Tooltip, { TooltipProps, tooltipClasses } from "@mui/material/Tooltip";

import VerticalLinearLogsCard from "@/components/Card/VerticalLinearLogsCard";
import { fetchByStaticRoute } from "@/utils";
import {
  API_GET_RECREATE_INDEX,
  API_VAR_PATH,
  API_GET_VAR_DDL_CHANGES,
} from "@/constants/api";

const CustomSlider = styled(Slider)({
  // color: "#52af77",
  height: "8px",
  "& .MuiSlider-track": {
    border: "none",
  },
  "& .MuiSlider-thumb": {
    height: 24,
    width: 24,
    backgroundColor: "#fff",
    border: "2px solid currentColor",
    "&:focus, &:hover, &.Mui-active, &.Mui-focusVisible": {
      boxShadow: "inherit",
    },
    "&:before": {
      display: "none",
    },
  },
  // "& .MuiSlider-valueLabel": {
  //   lineHeight: 1.2,
  //   fontSize: 12,
  //   background: "unset",
  //   padding: 0,
  //   width: 32,
  //   height: 32,
  //   borderRadius: "50% 50% 50% 0",
  //   backgroundColor: "#52af77",
  //   transformOrigin: "bottom left",
  //   transform: "translate(50%, -100%) rotate(-45deg) scale(0)",
  //   "&:before": { display: "none" },
  //   "&.MuiSlider-valueLabelOpen": {
  //     transform: "translate(50%, -100%) rotate(-45deg) scale(1)",
  //   },
  //   "& > *": {
  //     transform: "rotate(45deg)",
  //   },
  // },
});

const SliderTemplate = (props: {
  id: string;
  label: string;
  min: number;
  max: number;
  step: number;
  defaultValue: number;
}) => {
  const { id, label, min, max, step, defaultValue } = props;

  const [value, setValue] = React.useState<number>(defaultValue);

  const handleChange = (event: Event, newValue: number | number[]) => {
    setValue(newValue as number);
  };

  return (
    <>
      <Box
        id={id}
        sx={{
          display: "flex",
          alignItems: "center",
          justifyContent: "space-between",
        }}
      >
        <Typography component="div" variant="body2" color="#7C7C7C">
          {label}
        </Typography>
        <Typography component="div">{value}</Typography>
      </Box>
      <Box>
        <CustomSlider
          aria-label="tidb_ddl_reorg_worker_cnt"
          value={value}
          onChange={handleChange}
          step={step}
          min={min}
          max={max}
        />
        <Box
          sx={{
            display: "flex",
            alignItems: "center",
            justifyContent: "space-between",
            fontWeight: 500,
            fontSize: "8px",
            lineHeight: "150%",
            color: "#D1D1D1",
          }}
        >
          <Typography
            component="div"
            variant="body2"
            fontWeight="inherit"
            fontSize="inherit"
          >
            {min}
          </Typography>
          <Typography
            component="div"
            variant="body2"
            fontWeight="inherit"
            fontSize="inherit"
          >
            {max}
          </Typography>
        </Box>
      </Box>
    </>
  );
};

const option = {
  // title: {
  //   text: "Speed of index creation",
  // },
  tooltip: {
    trigger: "axis",
  },
  // legend: {
  //   data: ["Speed(rows/s)", "Row Count"],
  // },
  grid: {
    left: "10%",
    right: "4%",
    bottom: "3%",
    containLabel: true,
  },
  // toolbox: {
  //   feature: {
  //     saveAsImage: {},
  //   },
  // },
  xAxis: {
    type: "category",
    data: ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
    splitLine: {
      show: true,
      interval: 10,
      lineStyle: {
        type: "dashed",
        color: "lightgrey",
      },
    },
  },
  yAxis: {
    type: "value",
    splitLine: {
      show: true,
      lineStyle: {
        type: "dashed",
        color: "lightgrey",
      },
    },
  },
  series: [
    {
      name: "Speed(rows/s)",
      type: "line",
      data: [],
      // markLine: {
      //   data: [
      //     // 1st line we want to draw
      //     [
      //       // start point of the line
      //       // we have to defined line attributes only here (not in the end point)
      //       {
      //         xAxis: "Tue",
      //         yAxis: 0,
      //         symbol: "none",
      //         lineStyle: {
      //           // normal: {
      //           //   color: '#00F'
      //           // }
      //           color: "rgba(0,0,0,0.3)",
      //           width: 2,
      //         },
      //         label: {
      //           backgroundColor: "#fff",
      //           padding: 6,
      //           borderColor: "#E1E1E1",
      //           borderWidth: 1,
      //           borderRadius: 6,
      //           textColor: "#565656",
      //           formatter:
      //             "tidb_ddl_reorg_worker_cnt     2\ntidb_ddl_reorg_worker_cnt     2",
      //           // normal: {
      //           //   show: true,
      //           //   position: 'end',
      //           //   formatter: 'tidb_ddl_reorg_worker_cnt     2\ntidb_ddl_reorg_worker_cnt     2'
      //           // }
      //         },
      //       },
      //       // end point of the line
      //       {
      //         xAxis: "Tue",
      //         yAxis: 300,
      //         symbol: "none",
      //       },
      //     ],
      //   ],
      // },
    },
  ],
  visualMap: [
    {
      type: "continuous",
      min: 0,
      max: 300,
      // dimension: 3, // the fourth dimension of series.data (i.e. value[3]) is mapped
      seriesIndex: 0, // The fourth series is mapped.
      inRange: {
        // The visual configuration in the selected range
        color: [
          "#5E46E1",
          "#4047FF",
          "#4AD983",
          "#00FE84",
          "#FFF279",
          "#FF6F50",
          "#FF4040",
        ], // A list of colors that defines the graph color mapping
      },
    },
  ],
};

const sliders = [
  {
    id: "tidb_ddl_reorg_worker_cnt",
    label: "DDL Reorg Worker Count",
    min: 1,
    max: 32,
    step: 1,
    defaultValue: 3,
  },
  {
    id: "tidb_ddl_reorg_batch_size",
    label: "DDL Reorg Batch Size",
    min: 32,
    max: 1024,
    step: 32,
    defaultValue: 256,
  },
];

export type WorkingDDLJobType = {
  jobId: number;
  dbName: string;
  tableName: string;
  jobType: string;
  schemaState: string;
  schemaId: number;
  tableId: number;
  rowCount: number;
  createTime: string;
  startTime: string;
  endTime: string;
  state: string;
  query: string;
};

export type ProcessItemType = {
  recordTime: string;
  rowCount: number;
  speed: number;
};

export type LogType = {
  variableName: string;
  variableValue: string;
  modifiedBy: string;
};

const fetchWorkingDDLJobs = async (isPost?: boolean) => {
  const data:
    | {
        working: true;
        workingDDLJob: WorkingDDLJobType;
        process: ProcessItemType[];
      }
    | {
        working: false;
        lastDDLJob: WorkingDDLJobType;
        process: ProcessItemType[];
      } = await fetchByStaticRoute(API_GET_RECREATE_INDEX, {
    method: isPost ? "POST" : "GET",
  });
  return data;
};

const fetchVarChangeLogs = async (query?: {
  startTime?: string;
  endTime?: string;
}) => {
  const data: LogType[] = await fetchByStaticRoute(
    API_GET_VAR_DDL_CHANGES +
      `${
        query
          ? `&${Object.keys(query)
              .map((qk) => `${qk}=${query[qk as keyof typeof query]}`)
              .join("&")}`
          : ""
      }`
  );
  return data;
};

function boundsProcess(array: ProcessItemType[], field: "rowCount" | "speed") {
  return array.reduce(
    ([min, max], item) => [
      Math.min(item[field], min),
      Math.max(item[field], max),
    ],
    [Infinity, -Infinity]
  );
}

export function IndexCreationChart(props: any) {
  const [working, setWorking] = React.useState<boolean>(false);
  const [workingDDLJob, setWorkingDDLJob] =
    React.useState<WorkingDDLJobType | null>(null);
  const [process, setProcess] = React.useState<ProcessItemType[] | null>(null);
  const [jobStartTime, setJobStartTime] = React.useState<string | null>(null);
  const [jobEndTime, setJobEndTime] = React.useState<string | null>(null);
  const [loading, setLoading] = React.useState<boolean>(true);
  const [errorMsg, setErrorMsg] = React.useState<string | null>(null);
  const [varChangeLogs, setVarChangeLogs] = React.useState<LogType[]>([]);

  React.useEffect(() => {
    const fetchData = async () => {
      setLoading(true);
      setErrorMsg(null);
      try {
        const {
          working: w,
          // workingDDLJob: wdj,
          process: pr,
        } = await fetchWorkingDDLJobs();
        setWorking(w);
        // setWorkingDDLJob(wdj);
        const sortedProcess = pr.sort((a, b) =>
          a.recordTime.localeCompare(b.recordTime)
        );
        setProcess(sortedProcess);
        setJobStartTime(sortedProcess[0].recordTime);
        !w && setJobEndTime(sortedProcess[sortedProcess.length - 1].recordTime);
      } catch (error: any) {
        console.error(error);
        setErrorMsg(error.message);
      } finally {
        setLoading(false);
      }
    };

    const updateData = async () => {
      try {
        const {
          working: w,
          // workingDDLJob: wdj,
          process: pr,
        } = await fetchWorkingDDLJobs();
        setWorking(w);
        // setWorkingDDLJob(wdj);
        const sortedProcess = pr.sort((a, b) =>
          a.recordTime.localeCompare(b.recordTime)
        );
        setProcess(sortedProcess);
        setJobStartTime(sortedProcess[0].recordTime);
        !w && setJobEndTime(sortedProcess[sortedProcess.length - 1].recordTime);
      } catch (error: any) {
        console.error(error);
      }
    };

    fetchData();
    const interval = setInterval(updateData, 10000);
    return () => clearInterval(interval);
  }, []);

  React.useEffect(() => {
    const fetchData = async (
      startTime?: string | null,
      endTime?: string | null
    ) => {
      const queryBody: {
        startTime?: string;
        endTime?: string;
      } = {};
      startTime && (queryBody["startTime"] = startTime);
      endTime && (queryBody["endTime"] = endTime);
      try {
        const data = await fetchVarChangeLogs(queryBody);
        setVarChangeLogs(data);
      } catch (error: any) {
        console.error(error);
      }
    };

    jobStartTime && fetchData(jobStartTime, jobEndTime);
  }, [process, jobStartTime, jobEndTime]);

  const handleClick = async () => {
    setLoading(true);
    setErrorMsg(null);
    try {
      await fetchWorkingDDLJobs(true);
      const {
        working: w,
        // workingDDLJob: wdj,
        process: pr,
      } = await fetchWorkingDDLJobs();
      setWorking(w);
      // setWorkingDDLJob(wdj);
      setProcess(pr.sort((a, b) => a.recordTime.localeCompare(b.recordTime)));
    } catch (error: any) {
      console.error(error);
      setErrorMsg(error.message);
    } finally {
      setLoading(false);
    }
  };

  const optionMemo = React.useMemo(() => {
    if (process === null) {
      return option;
    }

    const [minRowCount, maxRowCount] = boundsProcess(process, "speed");

    const xAxisData = process.map((p) =>
      new Date(p.recordTime).toLocaleString()
    );
    const yAxisData = process.map((p) => p.speed);

    const getXAxisByInputTime = (inputTime: string) => {
      const targetProcessItem = process.find((p) => p.recordTime > inputTime);
      return targetProcessItem
        ? new Date(targetProcessItem.recordTime).toLocaleString()
        : "";
    };

    const getLastVarChangeLogs = (limit = 5) => {
      const lastBatchSizeItems = varChangeLogs.filter(
        (item) => item.variableName === "tidb_ddl_reorg_batch_size"
      );
      const lastWorkerCntItems = varChangeLogs.filter(
        (item) => item.variableName === "tidb_ddl_reorg_worker_cnt"
      );

      const maxLength = Math.min(
        lastBatchSizeItems.length,
        lastWorkerCntItems.length
      );

      if (maxLength === 0) {
        return null;
      }

      const results: {
        tidb_ddl_reorg_batch_size: LogType;
        tidb_ddl_reorg_worker_cnt: LogType;
        time: string;
      }[] = [];

      for (let i = 0, len = maxLength; i < len; i++) {
        const lastBatchSizeItem = lastBatchSizeItems[i];
        const lastWorkerCntItem = lastWorkerCntItems[i];

        const lastBatchSizeXAxisTime = getXAxisByInputTime(
          lastBatchSizeItem?.modifiedBy || ""
        );
        const lastWorkerCntXAxisTime = getXAxisByInputTime(
          lastWorkerCntItem?.modifiedBy || ""
        );

        if (lastBatchSizeXAxisTime && lastWorkerCntXAxisTime) {
          results.push({
            tidb_ddl_reorg_batch_size: lastBatchSizeItem,
            tidb_ddl_reorg_worker_cnt: lastWorkerCntItem,
            time: lastBatchSizeXAxisTime,
          });
        }
      }

      return results.slice(0, limit);
    };

    const lastVarChangeLogs = getLastVarChangeLogs();

    console.log(lastVarChangeLogs);

    return {
      ...option,
      xAxis: {
        ...option.xAxis,
        data: xAxisData,
      },
      series: [
        {
          ...option.series[0],
          data: yAxisData,
          markLine: {
            data:
              (lastVarChangeLogs &&
                lastVarChangeLogs.length > 0 &&
                lastVarChangeLogs.map((item) => [
                  {
                    xAxis: item.time,
                    yAxis: 0,
                    symbol: "none",
                    lineStyle: {
                      color: "rgba(0,0,0,0.3)",
                      width: 2,
                    },
                    label: {
                      backgroundColor: "#fff",
                      padding: 6,
                      borderColor: "#E1E1E1",
                      borderWidth: 1,
                      borderRadius: 6,
                      textColor: "#565656",
                      position: "end",
                      overflow: "break",
                      formatter: `batch_size :   ${item.tidb_ddl_reorg_batch_size.variableValue}\nworker_cnt :   ${item.tidb_ddl_reorg_worker_cnt.variableValue}`,
                    },
                  },
                  {
                    xAxis: item.time,
                    yAxis: maxRowCount,
                    symbol: "none",
                  },
                ])) ||
              [],
          },
        },
      ],
      visualMap: [
        {
          ...option.visualMap[0],
          min: 0,
          max: maxRowCount,
        },
      ],
    };
  }, [process, varChangeLogs]);

  console.log(optionMemo);

  return (
    <Grid container spacing={2}>
      <Grid xs={12} lg={8}>
        <StatusBarSpeed
          speed={process?.length && process[process?.length - 1].speed}
        />
        {loading && (
          <Box sx={{ display: "flex" }}>
            <CircularProgress />
          </Box>
        )}
        {!loading && process?.length && process.length > 0 && (
          <ReactEcharts option={optionMemo} />
        )}
      </Grid>
      <Grid xs={12} lg={4}>
        <StatusBarClock />
        {/*<StatusBarBusinessPeriod />*/}
        <StatusBarLogs logs={varChangeLogs} />
        <StatusBarIndexCfg
          vars={[`tidb_ddl_reorg_worker_cnt`, `tidb_ddl_reorg_batch_size`]}
        />
        <CommonStatusItem>
          <Button
            variant="contained"
            disabled={working || loading}
            onClick={handleClick}
            startIcon={working ? <CircularProgress size={20} /> : null}
          >
            {working ? `Creating Index` : `Start creating index`}
          </Button>
        </CommonStatusItem>
      </Grid>
      {/* <Grid container xs={12} md={4} spacing={2}>
        <Grid xs={12}>
          <Typography variant="h5">Modify logs</Typography>
          <VerticalLinearLogsCard />
        </Grid>
        <Grid xs={12}>
          <Stack>
            <Typography variant="h5">Modify the global variable</Typography>
            {sliders?.map((slider) => (
              <SliderTemplate
                key={slider.id}
                id={slider.id}
                label={slider.label}
                min={slider.min}
                max={slider.max}
                step={slider.step}
                defaultValue={slider.defaultValue}
              />
            ))}
          </Stack>
        </Grid>
      </Grid> */}
    </Grid>
  );
}

const StatusBarClock = () => {
  const [time, setTime] = React.useState(new Date());

  React.useEffect(() => {
    const interval = setInterval(() => {
      setTime(new Date());
    }, 1000);
    return () => clearInterval(interval);
  }, []);

  return (
    <CommonStatusItem title={`Current Time`}>
      <Typography
        component="div"
        fontWeight="bold"
        fontSize="24px"
        color="#565656"
      >
        {time.toLocaleTimeString()}
      </Typography>
    </CommonStatusItem>
  );
};

const StatusBarBusinessPeriod = () => {
  const [isPeak, setIsPeak] = React.useState(() => {
    const now = new Date();
    const hour = now.getUTCHours();
    return hour >= 16 && hour <= 24;
  });

  React.useEffect(() => {
    const interval = setInterval(() => {
      const now = new Date();
      const hour = now.getUTCHours();
      setIsPeak(hour >= 16 && hour <= 24);
    }, 60000);
    return () => clearInterval(interval);
  }, []);

  const BusinessPeriodTooltipContent = () => {
    return (
      <>
        <Box fontSize="10px" color="#565656">
          <Typography component="span" fontWeight="bold" fontSize="inherit">
            {`Peak: `}
          </Typography>
          <Typography component="span" fontSize="inherit">
            18:00 - 24:00 (UTC 0)
          </Typography>
        </Box>
        <Box fontSize="10px" color="#565656">
          <Typography component="span" fontWeight="bold" fontSize="inherit">
            {`Off-Peak: `}
          </Typography>
          <Typography component="span" fontSize="inherit">
            00:00 - 18:00 (UTC 0)
          </Typography>
        </Box>
      </>
    );
  };

  return (
    <>
      <CommonStatusItem
        title={`Business period`}
        tooltip={<BusinessPeriodTooltipContent />}
        tooltipProps={{
          placement: "right",
        }}
      >
        <Box
          sx={{
            display: "flex",
            alignItems: "center",
            gap: (theme) => theme.spacing(0.5),
          }}
        >
          <Box
            component="div"
            sx={{
              width: "12px",
              height: "12px",
              "&:before": {
                content: "''",
                display: "block",
                width: "12px",
                height: "12px",
                borderRadius: "6px",
                backgroundColor: isPeak ? "#FF4040" : "green",
              },
            }}
          />
          <Typography
            component="span"
            color="#565656"
            fontSize="24px"
            fontWeight="bold"
          >
            {isPeak ? `Peak` : `Off-peak`}
          </Typography>
        </Box>
      </CommonStatusItem>
    </>
  );
};

const StatusBarIndexCfgItem = (props: { title: string; value: string }) => {
  const { title, value } = props;

  return (
    <Box
      sx={{
        display: "flex",
        alignItems: "center",
        justifyContent: "space-between",
        gap: (theme) => theme.spacing(0.5),
        py: (theme) => theme.spacing(0.5),

        color: "#919EAA",
        fontSize: "12px",
      }}
    >
      <Typography component="div" fontSize="inherit">
        {title}
      </Typography>
      <Typography component="div" fontSize="inherit" color="#565656">
        {value}
      </Typography>
    </Box>
  );
};

const StatusBarIndexCfg = (props: { vars?: string[] }) => {
  const { vars = [] } = props;

  const [values, setValues] = React.useState<{ [key: string]: string }>({});

  React.useEffect(() => {
    const fetchVar = async (variable: string) => {
      try {
        const data = await fetchByStaticRoute(API_VAR_PATH + variable);
        setValues((prev) => ({ ...prev, [variable]: data.currentValue }));
      } catch (error) {
        console.error(error);
      }
    };
    if (vars.length > 0) {
      vars.forEach((item) => {
        fetchVar(item);
      });
    }
  }, [vars]);

  return (
    <>
      <CommonStatusItem title={`Settings`}>
        {vars.map((item) => (
          <StatusBarIndexCfgItem
            key={item}
            title={item}
            value={values[item] || "-"}
          />
        ))}
      </CommonStatusItem>
    </>
  );
};

const StatusBarSpeed = (props: { speed?: number | null }) => {
  const { speed } = props;

  return (
    <>
      {speed && speed > 0 && (
        <CommonStatusItem title={`Index creating speed`}>
          <Typography
            component="div"
            fontWeight="bold"
            fontSize="24px"
            color="#565656"
          >
            {`⚡️ ${speed} rows/s`}
          </Typography>
        </CommonStatusItem>
      )}
    </>
  );
};

const StatusBarLogs = (props: { logs: LogType[] }) => {
  const { logs } = props;

  return (
    <>
      {logs?.length > 0 && (
        <CommonStatusItem title={`Modify logs`}>
          <VerticalLinearLogsCard logs={logs} />
        </CommonStatusItem>
      )}
    </>
  );
};

const LightTooltip = styled(({ className, ...props }: TooltipProps) => (
  <Tooltip {...props} classes={{ popper: className }} />
))(({ theme }) => ({
  [`& .${tooltipClasses.tooltip}`]: {
    backgroundColor: theme.palette.common.white,
    color: "rgba(0, 0, 0, 0.87)",
    boxShadow: "none",
    border: "1px solid #E7E7E7",
    fontSize: 11,
  },
}));

const CommonStatusItem = (props: {
  title?: string | React.ReactNode;
  tooltip?: string | React.ReactNode;
  tooltipProps?: Partial<TooltipProps>;
  children: React.ReactNode;
}) => {
  const { title, tooltip, tooltipProps, children } = props;

  return (
    <Box
      sx={{
        display: "flex",
        flexDirection: "column",
        py: (theme) => theme.spacing(1),
      }}
    >
      <Box
        color="#919EAA"
        fontSize="12px"
        sx={{
          display: "flex",
          alignItems: "center",
          gap: (theme) => theme.spacing(0.5),
          mb: (theme) => theme.spacing(1),
        }}
      >
        {title && (
          <Typography color="inherit" fontSize="inherit" component="span">
            {title}
          </Typography>
        )}
        {tooltip && (
          <LightTooltip title={tooltip} {...tooltipProps}>
            <InfoOutlinedIcon color="inherit" fontSize="inherit" />
          </LightTooltip>
        )}
      </Box>
      <Box>{children}</Box>
    </Box>
  );
};
