import React, { useEffect, useState } from "react";
import {
  Box,
  Typography,
  Checkbox,
  Button,
  Tooltip,
  Paper,
  Grid,
} from "@mui/material";
import { Lock } from "@mui/icons-material";
import { toast } from "react-toastify";
import InputFactory from "./InputFactory.js";
import {
  updateGlobalConfig,
  getGlobalConfig,
} from "../../constants/apiEndPoints.js";
import useApiService from "../../services/apiService.js";
import "./GlobalConfig.css";

const updateConfigData = (selectedIds, fieldsToUpdate) => (prev) =>
    prev.map((item) => {
      if (!selectedIds.includes(item.Id)) return item;
      const field = fieldsToUpdate.find((f) => f.Id === item.Id);
      return { ...item, ProValue: field?.Value };
    });
function GlobalConfig() {
  const { postApi } = useApiService();
  const [configData, setConfigData] = useState([]);
  const [editableMap, setEditableMap] = useState({});
  const [selectedIds, setSelectedIds] = useState([]);
  const [originalConfigData, setOriginalConfigData] = useState([]);
  const [errors, setErrors] = useState({});
  const [isBulkMode, setIsBulkMode] = useState(false);

  useEffect(() => {
    fetchData();
  }, []);

  const fetchData = async () => {
    const payload = {
      SearchText: null,
      PageSize: 50,
      PageNumber: 1,
      IgnorePaging: true,
      Filter: { SortDirection: null, FilterColumn: null, FilterValue: null },
      SortOrder: null,
      SortColumn: null,
    };
    const response = await postApi(getGlobalConfig, payload);
    const normalized = (response?.Records || [])
      .sort((a, b) => a.FieldOrder - b.FieldOrder)
      .map((f) => ({ ...f, ProValue: f.ProValue || f.DefaultValue || "" }));
    setConfigData(normalized);
    setOriginalConfigData(JSON.parse(JSON.stringify(normalized)));
  };
  const isSafePattern = (pattern) => {
    try {
      const recheck = require("recheck");
      return recheck.isSafe(pattern);
    } catch (e) {
      console.warn("recheck unavailable or failed to validate pattern:", e);

      // Basic regex safety heuristics
      const tooLong = pattern.length > 1000;
      const hasLookahead = /\(\?[:=!<]/.test(pattern);
      const hasNestedQuantifiers = /\(\?.*\)\{0,\}/.test(pattern);
      const hasRepeatedQuantifiers = /[+*?]{2,}/.test(pattern);

      return !(tooLong || hasLookahead || hasNestedQuantifiers || hasRepeatedQuantifiers);
    }
  };

  const validateLength = (field, value) => {
    if (!["text", "textarea", "email", "phone"].includes(field.Type)) return "";
    if (value?.length < field.Min || value?.length > field.Max) {
      return `Length ${field.Min}-${field.Max}`;
    }
    return "";
  };
  const validateNumberRange = (field, value) => {
    if (field.Type !== "number") return "";
    const num = Number(value);
    if (num < field.Min || num > field.Max) {
      return `Value ${field.Min}-${field.Max}`;
    }
    return "";
  };
  const validatePattern = (field, value) => {
    if (field.Type === "list" || !field.Pattern || !value) return "";

    if (!isSafePattern(field.Pattern)) {
      return "Invalid regex pattern";
    }

    try {
      const regex = new RegExp(field.Pattern);
      if (!regex.test(value)) {
        return field?.ErrorText || "Invalid format";
      }
    } catch {
      return "Invalid regex pattern";
    }

    return "";
  };
  const validateField = (field, value) => (
      validateLength(field, value) ||
      validateNumberRange(field, value) ||
      validatePattern(field, value) ||
      ""
    );


  const handleCheckboxToggle = (id) => {
    setSelectedIds((prev) =>
      prev.includes(id) ? prev.filter((i) => i !== id) : [...prev, id]
    );
  };
  const handleInputChange = (id, newValue) => {
    setConfigData((prev) =>
      prev.map((d) => (d.Id === id ? { ...d, ProValue: `${newValue}` } : d))
    );
    const field = configData.find((d) => d.Id === id);
    if (!field) return;
    if (field.Type === "list") {
      return;
    }
    const error = validateField(field, newValue);
    setErrors((prev) => ({ ...prev, [id]: error }));
  };

  const handleEditClick = (id) => {
    setIsBulkMode(false);
    setEditableMap({ ...editableMap, [id]: true });
  };

  const handleSaveClick = async (id) => {
    const field = configData.find((d) => d.Id === id);
    const error = validateField(field, field.ProValue);
    if (error) {
      setErrors((prev) => ({ ...prev, [id]: error }));
      document.getElementById(`field-${id}`)?.focus();
      return;
    }
    const payload = {
      SearchText: null,
      PageSize: 0,
      PageNumber: 0,
      IgnorePaging: true,
      Filter: {
        Properties: [
          {
            Id: field.Id,
            Value: field.ProValue,
          },
        ],
      },
      SortOrder: null,
      SortColumn: null,
    };
    const saveDataResponse = await postApi(updateGlobalConfig, payload);
    if (saveDataResponse?.Records) {
      toast.success(
        saveDataResponse?.Records[0]?.Message || "Record updated successfully!"
      );
      setConfigData((prev) =>
        prev.map((d) => (d.Id === id ? { ...d, ProValue: field.ProValue } : d))
      );
      setOriginalConfigData((prev) =>
        prev.map((d) => (d.Id === id ? { ...d, ProValue: field.ProValue } : d))
      );
    }
    setEditableMap((prev) => ({ ...prev, [id]: false }));
    setSelectedIds((prev) => prev.filter((i) => i !== id));
    setErrors((prev) => ({ ...prev, [id]: "" }));
    fetchData();
  };

  const handleBulkEdit = () => {
    const newMap = {};
    selectedIds.forEach((id) => {
      const row = configData.find((r) => r.Id === id);
      if (row?.Editable) newMap[id] = true;
    });
    setEditableMap({ ...editableMap, ...newMap });
    setIsBulkMode(true);
  };

  const handleBulkSave = async () => {
    const { errors, updates } = collectFieldsToUpdate(selectedIds, configData);

    if (handleValidationErrors(errors, setErrors)) return;
    if (!updates?.length) return;

    const payload = buildPayload(updates);
    const response = await postApi(updateGlobalConfig, payload);

    processSaveResponse(
      response,
      selectedIds,
      updates,
      setConfigData,
      setOriginalConfigData,
      fetchData
    );
    resetBulkState(setEditableMap, setSelectedIds, setIsBulkMode, setErrors);
  };

  const collectFieldsToUpdate = (selectedIds, configData) => {
    const errors = {};
    const updates = [];

    for (const id of selectedIds) {
      const field = configData.find((d) => d.Id === id);
      const error = validateField(field, field.ProValue);
      if (error) {
        errors[id] = error;
      } else {
        updates.push({ Id: field.Id, Value: field.ProValue });
      }
    }

    return { errors, updates };
  };

  const handleValidationErrors = (errors, setErrors) => {
    if (!Object.keys(errors)?.length) return false;

    setErrors((prev) => ({ ...prev, ...errors }));
    const firstErrorId = Object.keys(errors)[0];
    document.getElementById(`field-${firstErrorId}`)?.focus();
    return true;
  };

  const buildPayload = (fieldsToUpdate) => ({
    SearchText: null,
    PageSize: 0,
    PageNumber: 0,
    IgnorePaging: true,
    Filter: { Properties: fieldsToUpdate },
    SortOrder: null,
    SortColumn: null,
  });

  const processSaveResponse = (
    response,
    selectedIds,
    fieldsToUpdate,
    setConfigData,
    setOriginalConfigData,
    fetchData
  ) => {
    if (!response?.Records) return;

    const domainErrors = [];
    const successMessages = [];

    // Separate domain errors and success messages
    response.Records.forEach((record) => {
      if (record.Message.includes("domain")) {
        domainErrors.push(record.Message);
      } else {
        successMessages.push(record.Message);
      }
    });

    // Show toast messages
    domainErrors.forEach((msg) =>
      toast.error(msg || "You can't delete domain because it has users assigned to this domain")
    );
    successMessages.forEach((msg) =>
      toast.success(msg || "Records updated successfully!")
    );

    // Update configuration data
    const updatedData = updateConfigData(selectedIds, fieldsToUpdate);

    setConfigData(updatedData);
    setOriginalConfigData(updatedData);

    if (domainErrors.length > 0) fetchData();
  };

  // Helper function to update config data



  const resetBulkState = (
    setEditableMap,
    setSelectedIds,
    setIsBulkMode,
    setErrors
  ) => {
    setEditableMap({});
    setSelectedIds([]);
    setIsBulkMode(false);
    setErrors({});
  };

  const handleCancelEdit = (id) => {
    const original = originalConfigData.find((d) => d.Id === id);
    setConfigData((prev) =>
      prev.map((d) => (d.Id === id ? { ...original } : d))
    );
    setEditableMap((prev) => ({ ...prev, [id]: false }));
    setSelectedIds((prev) => prev.filter((i) => i !== id));
    setErrors((prev) => ({ ...prev, [id]: "" }));
  };

  const handleCancelAll = () => {
    setConfigData(JSON.parse(JSON.stringify(originalConfigData)));
    setEditableMap({});
    setSelectedIds([]);
    setErrors({});
    setIsBulkMode(false);
  };

  return (
    <Box p={2}>
      <Typography variant="h5" fontWeight="bold" mb={2}>
        Configuration Editor
      </Typography>

      <Box display="flex" gap={2} alignItems="center" mb={2}>
        <Checkbox
          checked={selectedIds?.length > 0}
          onChange={(e) =>
            setSelectedIds(
              e.target.checked
                ? configData.filter((d) => d.Editable).map((d) => d.Id)
                : []
            )
          }
          style={{ marginLeft: "16px" }}
        />
        <Button
          variant="contained"
          onClick={handleBulkEdit}
          disabled={selectedIds?.length === 0 || isBulkMode}
        >
          Edit Selected
        </Button>
        {isBulkMode && selectedIds?.length > 0 && (
          <>
            <Button
              variant="contained"
              color="success"
              onClick={handleBulkSave}
            >
              Save Selected
            </Button>
            <Button variant="outlined" color="error" onClick={handleCancelAll}>
              Cancel Editing
            </Button>
          </>
        )}
      </Box>

      <Grid container spacing={2}>
        {configData.map((field) => {
          const isEditable = field.Editable && editableMap[field.Id];
          const error = errors[field.Id];
          return (
            <Grid item xs={12} key={field.Id}>
              <Paper
                elevation={2}
                sx={{
                  p: 2,
                  borderRadius: 2,
                  display: "flex",
                  alignItems: "center",
                  justifyContent: "flex-start",
                  gap: 2,
                  "&:hover": { boxShadow: 6 },
                }}
              >
                {/* Left: Selection */}
                <Checkbox
                  checked={selectedIds.includes(field.Id)}
                  disabled={!field.Editable}
                  onChange={() => handleCheckboxToggle(field.Id)}
                />

                {/* Middle: Label + Input */}
                <Box sx={{ flex: 1, maxWidth: "60%" }}>
                  <Typography fontWeight="bold" mb={2}>
                    {field.Label}{" "}
                    {!field.Editable && (
                      <Tooltip title="Not Editable">
                        <Lock
                          fontSize="small"
                          style={{ verticalAlign: "middle" }}
                        />
                      </Tooltip>
                    )}
                  </Typography>

                  <InputFactory
                    field={field}
                    disabled={!isEditable}
                    error={!!error}
                    helperText={error || field.HelpText}
                    onChange={(val) => handleInputChange(field.Id, val)}
                  />
                </Box>

                {/* Right: Actions */}
                <Box display="flex" alignItems="center" gap={1}>
                  {editableMap[field.Id] ? (
                    <>
                      <Button
                        size="small"
                        variant="contained"
                        color="success"
                        disabled={!!error}
                        onClick={() => handleSaveClick(field.Id)}
                      >
                        Save
                      </Button>
                      <Button
                        size="small"
                        variant="outlined"
                        color="error"
                        onClick={() => handleCancelEdit(field.Id)}
                      >
                        Cancel
                      </Button>
                    </>
                  ) : (
                    <Button
                      size="small"
                      variant="contained"
                      disabled={!field.Editable}
                      onClick={() => handleEditClick(field.Id)}
                    >
                      Edit
                    </Button>
                  )}
                </Box>
              </Paper>
            </Grid>
          );
        })}
      </Grid>
    </Box>
  );
}



export default GlobalConfig;
