import ApplyIcon from "@mui/icons-material/Check";
import PaletteIcon from "@mui/icons-material/PaletteOutlined";
import ResetIcon from "@mui/icons-material/Refresh";
import {
  Box,
  Button,
  Checkbox,
  Chip,
  Divider,
  FormControl,
  FormControlLabel,
  IconButton,
  InputLabel,
  MenuItem,
  Select,
  Slider,
  TextField,
  Tooltip,
  Typography,
} from "@mui/material";
import React from "react";

import {
  CLASSIFICATION_METHODS,
  COLOR_TYPE_OPTIONS,
  GRADIENT_PALETTES,
  RAINBOW_PALETTES,
  SINGLE_COLOR_PALETTES,
} from "./styleEditorPresets";
import type {
  ClassificationMethod,
  ColorType,
  StyleEditorFormProps,
} from "./styleEditorTypes";
import {
  getDefaultCustomColors,
  hexToRgba,
  resolveStyleColors,
  rgbaToHex,
} from "./styleEditorUtils";

const sectionSx = { px: 2, py: 1.5 } as const;
const sliderSx = { mx: 1, width: "calc(100% - 16px)" } as const;

type PalettePreview = { name: string; colors: string[]; index: number };

const getPalettePreviews = (colorType: ColorType): PalettePreview[] => {
  switch (colorType) {
    case "single":
      return SINGLE_COLOR_PALETTES.map((palette, index) => ({
        name: `单色 ${index + 1}`,
        colors: [palette.color],
        index,
      }));
    case "gradient":
      return GRADIENT_PALETTES.map((palette, index) => ({
        name: palette.name,
        colors: [palette.start, palette.end],
        index,
      }));
    case "rainbow":
      return RAINBOW_PALETTES.map((palette, index) => ({
        name: palette.name,
        colors: palette.colors,
        index,
      }));
    default:
      return [];
  }
};

const getSelectedPaletteIndex = (styleConfig: StyleEditorFormProps["styleConfig"]) => {
  switch (styleConfig.colorType) {
    case "single":
      return styleConfig.singlePaletteIndex;
    case "gradient":
      return styleConfig.gradientPaletteIndex;
    case "rainbow":
      return styleConfig.rainbowPaletteIndex;
    default:
      return -1;
  }
};

const selectPalette = (colorType: ColorType, index: number) => {
  switch (colorType) {
    case "single":
      return { singlePaletteIndex: index };
    case "gradient":
      return { gradientPaletteIndex: index };
    case "rainbow":
      return { rainbowPaletteIndex: index };
    default:
      return {};
  }
};

const StyleEditorForm: React.FC<StyleEditorFormProps> = ({
  renderLayers,
  selectedRenderLayer,
  styleConfig,
  setStyleConfig,
  availableProperties,
  onLayerChange,
  onPropertyChange,
  onClassificationMethodChange,
  onSegmentsChange,
  onCustomBreakChange,
  onColorTypeChange,
  onApply,
  onReset,
  validationErrors,
  isDirty,
  isApplying,
}) => {
  const layerType = selectedRenderLayer?.get("type");
  const previewColors = resolveStyleColors(styleConfig);
  const selectedProperty = availableProperties.some(
    (property) => property.value === styleConfig.property,
  )
    ? styleConfig.property
    : "";

  const setCustomColor = (index: number, hex: string) => {
    setStyleConfig((previous) => {
      const customColors = getDefaultCustomColors(
        previous.segments,
        previous.customColors,
      );
      customColors[index] = hexToRgba(hex);
      return { ...previous, customColors };
    });
  };

  const renderPalette = () => {
    const palettes = getPalettePreviews(styleConfig.colorType);
    if (palettes.length === 0) return null;
    const selectedIndex = getSelectedPaletteIndex(styleConfig);

    return (
      <Box sx={{ display: "grid", gridTemplateColumns: "repeat(2, minmax(0, 1fr))", gap: 1 }}>
        {palettes.map((palette) => (
          <Tooltip key={palette.name} title={palette.name} placement="top">
            <Box
              component="button"
              type="button"
              aria-label={palette.name}
              onClick={() =>
                setStyleConfig((previous) => ({
                  ...previous,
                  ...selectPalette(previous.colorType, palette.index),
                }))
              }
              sx={{
                display: "flex",
                height: 30,
                p: 0.5,
                overflow: "hidden",
                cursor: "pointer",
                bgcolor: "background.paper",
                border: "1px solid",
                borderColor: selectedIndex === palette.index ? "primary.main" : "divider",
                borderRadius: 1,
                boxShadow: selectedIndex === palette.index ? "0 0 0 1px currentColor" : "none",
              }}
            >
              {palette.colors.map((color, index) => (
                <Box key={`${color}-${index}`} sx={{ flex: 1, bgcolor: color }} />
              ))}
            </Box>
          </Tooltip>
        ))}
      </Box>
    );
  };

  return (
    <Box
      sx={{
        position: "absolute",
        top: 72,
        left: 12,
        zIndex: 1300,
        width: "min(380px, calc(100vw - 24px))",
        maxHeight: "calc(100dvh - 92px)",
        display: "flex",
        flexDirection: "column",
        bgcolor: "background.paper",
        border: "none",
        borderRadius: "12px",
        boxShadow:
          "0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04)",
        backdropFilter: "blur(8px)",
        opacity: 0.95,
        transition: "opacity 0.3s ease-in-out",
        overflow: "hidden",
        "&:hover": {
          opacity: 1,
        },
      }}
    >
      <Box
        sx={{
          px: 2.5,
          py: 1.5,
          display: "flex",
          alignItems: "center",
          gap: 1,
          bgcolor: "rgba(255,255,255,0.98)",
          color: "text.primary",
          borderBottom: "1px solid",
          borderColor: "divider",
        }}
      >
        <PaletteIcon fontSize="small" sx={{ color: "#257DD4" }} />
        <Typography variant="subtitle1" sx={{ fontWeight: 600, flex: 1 }}>
          图层样式
        </Typography>
        {isDirty && (
          <Chip
            label="待应用"
            size="small"
            sx={{
              height: 24,
              color: "warning.dark",
              bgcolor: "warning.50",
              border: "1px solid",
              borderColor: "warning.200",
            }}
          />
        )}
      </Box>

      <Box sx={{ overflowY: "auto", overflowX: "hidden", minHeight: 0 }}>
        <Box sx={sectionSx}>
          <Typography variant="overline" color="text.secondary">
            图层与数据
          </Typography>
          <Box sx={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 1.25, mt: 0.5 }}>
            <FormControl size="small" fullWidth>
              <InputLabel>图层</InputLabel>
              <Select
                label="图层"
                value={selectedRenderLayer?.get("value") || ""}
                onChange={(event) => onLayerChange(String(event.target.value))}
              >
                {renderLayers.map((layer) => (
                  <MenuItem key={layer.get("value")} value={layer.get("value")}>
                    {layer.get("name")}
                  </MenuItem>
                ))}
              </Select>
            </FormControl>
            <FormControl size="small" fullWidth>
              <InputLabel>属性</InputLabel>
              <Select
                label="属性"
                value={selectedProperty}
                onChange={(event) => onPropertyChange(String(event.target.value))}
              >
                {availableProperties.map((property) => (
                  <MenuItem key={property.value} value={property.value}>
                    {property.name}
                  </MenuItem>
                ))}
              </Select>
            </FormControl>
            <FormControl size="small" fullWidth>
              <InputLabel>分级方法</InputLabel>
              <Select
                label="分级方法"
                value={styleConfig.classificationMethod}
                onChange={(event) =>
                  onClassificationMethodChange(event.target.value as ClassificationMethod)
                }
              >
                {CLASSIFICATION_METHODS.map((method) => (
                  <MenuItem key={method.value} value={method.value}>
                    {method.name}
                  </MenuItem>
                ))}
              </Select>
            </FormControl>
            <TextField
              size="small"
              label="分类数量"
              type="number"
              value={styleConfig.segments}
              onChange={(event) => onSegmentsChange(Number(event.target.value))}
              slotProps={{ htmlInput: { min: 2, max: 10, step: 1 } }}
            />
          </Box>
        </Box>

        <Divider />
        <Box sx={sectionSx}>
          <Typography variant="overline" color="text.secondary">
            分级与色带
          </Typography>
          <FormControl size="small" fullWidth sx={{ mt: 0.5, mb: 1 }}>
            <InputLabel>颜色方案</InputLabel>
            <Select
              label="颜色方案"
              value={styleConfig.colorType}
              onChange={(event) => onColorTypeChange(event.target.value as ColorType)}
            >
              {COLOR_TYPE_OPTIONS.map((option) => (
                <MenuItem key={option.value} value={option.value}>
                  {option.label}
                </MenuItem>
              ))}
            </Select>
          </FormControl>
          {renderPalette()}

          {styleConfig.classificationMethod === "custom_breaks" && (
            <Box sx={{ mt: 1.25, display: "grid", gap: 0.75 }}>
              {Array.from({ length: styleConfig.segments }, (_, index) => (
                <Box
                  key={index}
                  sx={{
                    display: "grid",
                    gridTemplateColumns:
                      styleConfig.colorType === "custom" ? "32px 1fr 12px 1fr" : "12px 1fr 12px 1fr",
                    gap: 0.75,
                    alignItems: "center",
                  }}
                >
                  {styleConfig.colorType === "custom" ? (
                    <Tooltip title={`区间 ${index + 1} 颜色`}>
                      <Box
                        component="input"
                        type="color"
                        aria-label={`区间 ${index + 1} 颜色`}
                        value={rgbaToHex(styleConfig.customColors?.[index] || previewColors[index])}
                        onChange={(event: React.ChangeEvent<HTMLInputElement>) =>
                          setCustomColor(index, event.target.value)
                        }
                        sx={{ width: 32, height: 30, p: 0, border: 0, bgcolor: "transparent" }}
                      />
                    </Tooltip>
                  ) : (
                    <Box sx={{ width: 10, height: 24, bgcolor: previewColors[index], borderRadius: 0.5 }} />
                  )}
                  <TextField
                    size="small"
                    type="number"
                    value={Number.isFinite(styleConfig.customBreaks?.[index]) ? styleConfig.customBreaks?.[index] : ""}
                    onChange={(event) => onCustomBreakChange(index, event.target.value)}
                    inputProps={{ "aria-label": `区间 ${index + 1} 下界`, step: 0.1 }}
                  />
                  <Typography variant="caption" color="text.secondary" textAlign="center">
                    至
                  </Typography>
                  <TextField
                    size="small"
                    type="number"
                    value={Number.isFinite(styleConfig.customBreaks?.[index + 1]) ? styleConfig.customBreaks?.[index + 1] : ""}
                    onChange={(event) => onCustomBreakChange(index + 1, event.target.value)}
                    inputProps={{ "aria-label": `区间 ${index + 1} 上界`, step: 0.1 }}
                  />
                </Box>
              ))}
            </Box>
          )}
        </Box>

        <Divider />
        <Box sx={sectionSx}>
          <Typography variant="overline" color="text.secondary">
            符号
          </Typography>
          {layerType === "point" ? (
            <Box sx={{ mt: 0.5 }}>
              <Typography variant="caption">
                节点半径 {styleConfig.minSize} - {styleConfig.maxSize}px
              </Typography>
              <Slider
                value={[styleConfig.minSize, styleConfig.maxSize]}
                onChange={(_, value) => {
                  const [minSize, maxSize] = value as number[];
                  setStyleConfig((previous) => ({ ...previous, minSize, maxSize }));
                }}
                min={2}
                max={16}
                step={1}
                size="small"
                sx={sliderSx}
              />
            </Box>
          ) : (
            <Box sx={{ mt: 0.5 }}>
              <FormControlLabel
                control={
                  <Checkbox
                    size="small"
                    checked={styleConfig.adjustWidthByProperty}
                    onChange={(event) =>
                      setStyleConfig((previous) => ({
                        ...previous,
                        adjustWidthByProperty: event.target.checked,
                      }))
                    }
                  />
                }
                label={<Typography variant="body2">按数值调整线宽</Typography>}
              />
              <Typography variant="caption">
                {styleConfig.adjustWidthByProperty
                  ? `${styleConfig.minStrokeWidth} - ${styleConfig.maxStrokeWidth}px`
                  : `${styleConfig.fixedStrokeWidth}px`}
              </Typography>
              <Slider
                value={
                  styleConfig.adjustWidthByProperty
                    ? [styleConfig.minStrokeWidth, styleConfig.maxStrokeWidth]
                    : styleConfig.fixedStrokeWidth
                }
                onChange={(_, value) =>
                  setStyleConfig((previous) =>
                    Array.isArray(value)
                      ? { ...previous, minStrokeWidth: value[0], maxStrokeWidth: value[1] }
                      : { ...previous, fixedStrokeWidth: value },
                  )
                }
                min={1}
                max={12}
                step={0.5}
                size="small"
                sx={sliderSx}
              />
            </Box>
          )}
          <Typography variant="caption">透明度 {Math.round(styleConfig.opacity * 100)}%</Typography>
          <Slider
            value={styleConfig.opacity}
            onChange={(_, value) =>
              setStyleConfig((previous) => ({ ...previous, opacity: value as number }))
            }
            min={0.1}
            max={1}
            step={0.05}
            size="small"
            sx={sliderSx}
          />
        </Box>

        <Divider />
        <Box sx={{ ...sectionSx, display: "flex", gap: 2 }}>
          <FormControlLabel
            control={
              <Checkbox
                size="small"
                checked={styleConfig.showLabels}
                onChange={(event) =>
                  setStyleConfig((previous) => ({ ...previous, showLabels: event.target.checked }))
                }
              />
            }
            label={<Typography variant="body2">数值标注</Typography>}
          />
          <FormControlLabel
            control={
              <Checkbox
                size="small"
                checked={styleConfig.showId}
                onChange={(event) =>
                  setStyleConfig((previous) => ({ ...previous, showId: event.target.checked }))
                }
              />
            }
            label={<Typography variant="body2">设施 ID</Typography>}
          />
        </Box>
      </Box>

      <Divider />
      <Box sx={{ px: 2, py: 1.25 }}>
        {validationErrors[0] && (
          <Typography variant="caption" color="error" sx={{ display: "block", mb: 0.75 }}>
            {validationErrors[0]}
          </Typography>
        )}
        <Box sx={{ display: "flex", justifyContent: "space-between", gap: 1 }}>
          <Tooltip title="恢复默认样式">
            <IconButton size="small" onClick={onReset} aria-label="恢复默认样式">
              <ResetIcon fontSize="small" />
            </IconButton>
          </Tooltip>
          <Button
            variant="contained"
            size="small"
            startIcon={<ApplyIcon />}
            onClick={onApply}
            disabled={!isDirty || validationErrors.length > 0 || isApplying}
          >
            {isApplying ? "应用中" : "应用"}
          </Button>
        </Box>
      </Box>
    </Box>
  );
};

export default StyleEditorForm;
