import { useEffect, useState, useRef, useMemo } from "react";
import type { ReactElement } from "react";
import { useForm } from "react-hook-form";
import { zodResolver } from "@hookform/resolvers/zod";
import { z } from "zod";
import { Loader2, ChevronDown, ChevronRight } from "lucide-react";
import {
  Modal,
  FormField,
  PrimaryButton,
  SecondaryButton,
} from "@/components/shared";
import type { Role, UpdateRoleRequest } from "@/types/role";
import { useAppSelector } from "@/hooks/redux-hooks";

// Utility function to generate code from name
const generateCodeFromName = (name: string): string => {
  return name
    .toLowerCase()
    .trim()
    .replace(/[^a-z0-9\s]/g, "") // Remove special characters except spaces
    .replace(/\s+/g, "_") // Replace spaces with underscores
    .replace(/_+/g, "_") // Replace multiple underscores with single underscore
    .replace(/^_|_$/g, ""); // Remove leading/trailing underscores
};

// All available resources
const ALL_RESOURCES = [
  "users",
  // 'tenants',
  "roles",
  "permissions",
  // 'user_roles',
  // 'user_tenants',
  // 'sessions',
  // 'api_keys',
  // 'api_key_permissions',
  "projects",
  "document",
  "audit",
  "security",
  "workflow",
  "training",
  "capa",
  "supplier",
  "reports",
  "notifications",
  "files",
  "settings",
  // 'modules',
  "audit_logs",
  // 'event_logs',
  // 'health_history',
  "qms_connections",
  "qms_sync_jobs",
  "qms_sync_conflicts",
  "qms_entity_mappings",
  "ai",
  "qms",
];

// All available actions
const ALL_ACTIONS = ["create", "read", "update", "delete"];

// Validation schema
const editRoleSchema = z.object({
  name: z.string().min(1, "Role name is required"),
  code: z
    .string()
    .min(1, "Code is required")
    .regex(
      /^[a-z]+(_[a-z]+)*$/,
      "Code must be lowercase and use '_' for separation (e.g. abc_def)",
    ),
  description: z.string().min(1, "Description is required"),
  permissions: z
    .array(
      z.object({
        resource: z.string(),
        action: z.string(),
      }),
    )
    .optional()
    .nullable(),
});

type EditRoleFormData = z.infer<typeof editRoleSchema>;

interface EditRoleModalProps {
  isOpen: boolean;
  onClose: () => void;
  roleId: string | null;
  onLoadRole: (id: string) => Promise<Role>;
  onSubmit: (id: string, data: UpdateRoleRequest) => Promise<void>;
  isLoading?: boolean;
  defaultTenantId?: string; // If provided, automatically include tenant_id in request body
}

export const EditRoleModal = ({
  isOpen,
  onClose,
  roleId,
  onLoadRole,
  onSubmit,
  isLoading = false,
  defaultTenantId,
}: EditRoleModalProps): ReactElement | null => {
  const [isLoadingRole, setIsLoadingRole] = useState<boolean>(false);
  const [loadError, setLoadError] = useState<string | null>(null);
  const loadedRoleIdRef = useRef<string | null>(null);
  const permissions = useAppSelector((state) => state.auth.permissions);
  const roles = useAppSelector((state) => state.auth.roles);
  const tenantIdFromAuth = useAppSelector((state) => state.auth.tenantId);
  const isSuperAdmin = roles.includes("super_admin");
  const [selectedPermissions, setSelectedPermissions] = useState<
    Array<{ resource: string; action: string }>
  >([]);
  const [expandedResources, setExpandedResources] = useState<Set<string>>(
    new Set(),
  );

  const {
    register,
    handleSubmit,
    setValue,
    watch,
    reset,
    setError,
    clearErrors,
    formState: { errors },
  } = useForm<EditRoleFormData>({
    resolver: zodResolver(editRoleSchema),
    defaultValues: {
      permissions: [],
    },
  });

  const nameValue = watch("name");

  // Auto-generate code from name
  useEffect(() => {
    if (nameValue) {
      const generatedCode = generateCodeFromName(nameValue);
      setValue("code", generatedCode, { shouldValidate: true });
    }
  }, [nameValue, setValue]);

  // Build available resources and actions based on user permissions
  const availableResourcesAndActions = useMemo(() => {
    const resourceMap = new Map<string, Set<string>>();

    permissions.forEach((perm) => {
      const { resource, action } = perm;

      if (resource === "*") {
        // If resource is *, show all resources
        ALL_RESOURCES.forEach((res) => {
          if (!resourceMap.has(res)) {
            resourceMap.set(res, new Set());
          }
          const actions = resourceMap.get(res)!;
          if (action === "*") {
            // If action is also *, add all actions
            ALL_ACTIONS.forEach((act) => actions.add(act));
          } else {
            actions.add(action);
          }
        });
      } else {
        // Specific resource
        if (!resourceMap.has(resource)) {
          resourceMap.set(resource, new Set());
        }
        const actions = resourceMap.get(resource)!;
        if (action === "*") {
          // If action is *, add all actions for this resource
          ALL_ACTIONS.forEach((act) => actions.add(act));
        } else {
          actions.add(action);
        }
      }
    });

    return resourceMap;
  }, [permissions]);

  // Check if a resource has any selected actions
  const hasSelectedActions = (
    resource: string,
    actions: Set<string>,
  ): boolean => {
    return Array.from(actions).some((action) => {
      return selectedPermissions.some((p) => {
        // Check for exact match
        if (p.resource === resource && p.action === action) return true;
        // Check for wildcard resource with exact action
        if (p.resource === "*" && p.action === action) return true;
        // Check for exact resource with wildcard action
        if (p.resource === resource && p.action === "*") return true;
        // Check for wildcard resource with wildcard action
        if (p.resource === "*" && p.action === "*") return true;
        return false;
      });
    });
  };

  // Toggle resource expansion
  const toggleResource = (resource: string) => {
    setExpandedResources((prev) => {
      const newSet = new Set(prev);
      if (newSet.has(resource)) {
        newSet.delete(resource);
      } else {
        newSet.add(resource);
      }
      return newSet;
    });
  };

  // Handle permission checkbox change
  const handlePermissionChange = (
    resource: string,
    action: string,
    checked: boolean,
  ) => {
    setSelectedPermissions((prev) => {
      const newPerms = [...prev];
      if (checked) {
        // Add permission if not already exists
        if (
          !newPerms.some((p) => p.resource === resource && p.action === action)
        ) {
          newPerms.push({ resource, action });
        }
      } else {
        // Remove permission
        return newPerms.filter(
          (p) => !(p.resource === resource && p.action === action),
        );
      }
      return newPerms;
    });
  };

  // Update form value when permissions change
  useEffect(() => {
    setValue(
      "permissions",
      selectedPermissions.length > 0 ? selectedPermissions : [],
    );
  }, [selectedPermissions, setValue]);

  // Expand resources that have selected permissions when role is loaded
  useEffect(() => {
    if (
      selectedPermissions.length > 0 &&
      availableResourcesAndActions.size > 0
    ) {
      const resourcesWithPermissions = new Set<string>();
      selectedPermissions.forEach((perm) => {
        if (perm.resource === "*") {
          // If wildcard resource, expand all available resources
          availableResourcesAndActions.forEach((_, resource) => {
            resourcesWithPermissions.add(resource);
          });
        } else if (availableResourcesAndActions.has(perm.resource)) {
          // Only expand if resource exists in available resources
          resourcesWithPermissions.add(perm.resource);
        }
      });
      // Only update if we have resources to expand and they're not already expanded
      if (resourcesWithPermissions.size > 0) {
        setExpandedResources((prev) => {
          const newSet = new Set(prev);
          resourcesWithPermissions.forEach((resource) => {
            if (!newSet.has(resource)) {
              newSet.add(resource);
            }
          });
          return newSet;
        });
      }
    }
  }, [selectedPermissions, availableResourcesAndActions]);

  // Load role data when modal opens - only load once per roleId
  useEffect(() => {
    if (isOpen && roleId) {
      // Only load if this is a new roleId or modal was closed and reopened
      if (loadedRoleIdRef.current !== roleId) {
        const loadRole = async (): Promise<void> => {
          try {
            setIsLoadingRole(true);
            setLoadError(null);
            clearErrors();
            const role = await onLoadRole(roleId);
            loadedRoleIdRef.current = roleId;

            // Set permissions (always set, even if empty array)
            const rolePermissions = role.permissions || [];
            setSelectedPermissions(rolePermissions);
            setValue("permissions", rolePermissions);

            // Expand resources that have selected permissions
            // This will be handled by useEffect after availableResourcesAndActions is computed

            reset({
              name: role.name,
              code: role.code,
              description: role.description || "",
              permissions: rolePermissions,
            });
          } catch (err: any) {
            setLoadError(
              err?.response?.data?.error?.message ||
                "Failed to load role details",
            );
          } finally {
            setIsLoadingRole(false);
          }
        };
        loadRole();
      }
    } else if (!isOpen) {
      // Only reset when modal is closed
      loadedRoleIdRef.current = null;
      setSelectedPermissions([]);
      reset({
        name: "",
        code: "",
        description: "",
        permissions: [],
      });
      setLoadError(null);
      clearErrors();
    }
  }, [
    isOpen,
    roleId,
    onLoadRole,
    reset,
    clearErrors,
    setValue,
    isSuperAdmin,
    defaultTenantId,
    tenantIdFromAuth,
  ]);

  const handleFormSubmit = async (data: EditRoleFormData): Promise<void> => {
    if (!roleId) return;

    clearErrors();
    try {
      const submitData = {
        ...data,
        // For super_admin, always include tenant_id if defaultTenantId is provided
        tenant_id: isSuperAdmin
          ? defaultTenantId || undefined
          : defaultTenantId || undefined,
        permissions:
          selectedPermissions.length > 0 ? selectedPermissions : undefined,
      };
      await onSubmit(roleId, submitData as UpdateRoleRequest);
      // Only reset form on success - this will be handled by parent closing modal
    } catch (error: any) {
      // Don't reset form on error - keep the form data and show errors
      // Handle validation errors from API
      if (
        error?.response?.data?.details &&
        Array.isArray(error.response.data.details)
      ) {
        const validationErrors = error.response.data.details;
        validationErrors.forEach(
          (detail: { path: string; message: string }) => {
            if (
              detail.path === "name" ||
              detail.path === "code" ||
              detail.path === "description" ||
              detail.path === "permissions"
            ) {
              setError(detail.path as keyof EditRoleFormData, {
                type: "server",
                message: detail.message,
              });
            }
          },
        );
      } else {
        // Handle general errors
        const errorObj = error?.response?.data?.error;
        const errorMessage =
          (typeof errorObj === "object" &&
          errorObj !== null &&
          "message" in errorObj
            ? errorObj.message
            : null) ||
          (typeof errorObj === "string" ? errorObj : null) ||
          error?.response?.data?.message ||
          error?.message ||
          "Failed to update role. Please try again.";
        setError("root", {
          type: "server",
          message:
            typeof errorMessage === "string"
              ? errorMessage
              : "Failed to update role. Please try again.",
        });
      }
      // Re-throw error to prevent form from thinking it succeeded
      throw error;
    }
  };

  return (
    <Modal
      isOpen={isOpen}
      onClose={onClose}
      title="Edit Role"
      description="Update role by setting permissions and role type."
      maxWidth="lg"
      footer={
        <>
          <SecondaryButton
            type="button"
            onClick={onClose}
            disabled={isLoading || isLoadingRole}
            className="px-4 py-2.5 text-sm"
          >
            Cancel
          </SecondaryButton>
          <PrimaryButton
            type="button"
            onClick={handleSubmit(handleFormSubmit)}
            disabled={isLoading || isLoadingRole}
            size="default"
            className="px-4 py-2.5 text-sm"
          >
            {isLoading ? "Updating..." : "Update Role"}
          </PrimaryButton>
        </>
      }
    >
      {isLoadingRole && (
        <div className="flex items-center justify-center py-12">
          <Loader2 className="w-6 h-6 text-[#112868] animate-spin" />
        </div>
      )}

      {/* General Error Display - Always visible */}
      {errors.root && (
        <div className="p-4 bg-[rgba(239,68,68,0.1)] border border-[#ef4444] rounded-md mb-4 mx-5 mt-5">
          <p className="text-sm text-[#ef4444]">{errors.root.message}</p>
        </div>
      )}

      {loadError && (
        <div className="p-4 bg-[rgba(239,68,68,0.1)] border border-[#ef4444] rounded-md mb-4 mx-5">
          <p className="text-sm text-[#ef4444]">{loadError}</p>
        </div>
      )}

      {!isLoadingRole && (
        <form
          onSubmit={handleSubmit(handleFormSubmit)}
          className="p-5 flex flex-col gap-0"
        >
          {/* Role Name and Role Code Row */}
          <div className="grid grid-cols-2 gap-5 pb-4">
            <FormField
              label="Role Name"
              required
              placeholder="Enter Text Here"
              error={errors.name?.message}
              {...register("name")}
            />

            <FormField
              label="Role Code"
              required
              placeholder="Auto-generated from name"
              error={errors.code?.message}
              {...register("code")}
              disabled
              className="bg-[#f3f4f6] cursor-not-allowed"
            />
          </div>

          {/* Description */}
          <FormField
            label="Description"
            required
            placeholder="Enter Text Here"
            error={errors.description?.message}
            {...register("description")}
          />

          {/* Permissions Section */}
          <div className="pb-4">
            <label className="flex items-center gap-1.5 text-[13px] font-medium text-[#0e1b2a] mb-3">
              <span>Permissions</span>
            </label>
            {errors.permissions && (
              <p className="text-sm text-[#ef4444] mb-2">
                {errors.permissions.message}
              </p>
            )}
            <div className="border border-[rgba(0,0,0,0.08)] rounded-md p-4">
              {Array.from(availableResourcesAndActions.entries()).length ===
              0 ? (
                <p className="text-sm text-[#6b7280]">
                  No permissions available
                </p>
              ) : (
                <div className="space-y-2">
                  {Array.from(availableResourcesAndActions.entries()).map(
                    ([resource, actions]) => {
                      const isExpanded = expandedResources.has(resource);
                      const hasSelected = hasSelectedActions(resource, actions);
                      return (
                        <div
                          key={resource}
                          className={`border border-[rgba(0,0,0,0.08)] rounded-md overflow-hidden transition-colors ${
                            hasSelected
                              ? "bg-[rgba(17,40,104,0.05)]"
                              : "bg-white"
                          }`}
                        >
                          <button
                            type="button"
                            onClick={() => toggleResource(resource)}
                            className="w-full flex items-center justify-between p-3 hover:bg-[rgba(0,0,0,0.02)] transition-colors"
                          >
                            <div className="flex items-center gap-2">
                              {isExpanded ? (
                                <ChevronDown className="w-4 h-4 text-[#0e1b2a]" />
                              ) : (
                                <ChevronRight className="w-4 h-4 text-[#0e1b2a]" />
                              )}
                              <span
                                className={`font-medium text-sm capitalize ${
                                  hasSelected
                                    ? "text-[#112868]"
                                    : "text-[#0e1b2a]"
                                }`}
                              >
                                {resource.replace(/_/g, " ")}
                              </span>
                              {hasSelected && (
                                <span className="text-xs text-[#112868] bg-[rgba(17,40,104,0.1)] px-2 py-0.5 rounded">
                                  Selected
                                </span>
                              )}
                            </div>
                          </button>
                          {isExpanded && (
                            <div className="px-3 pb-3 pt-2 border-t border-[rgba(0,0,0,0.05)]">
                              <div className="flex flex-wrap gap-4">
                                {Array.from(actions).map((action) => {
                                  const isChecked = selectedPermissions.some(
                                    (p) => {
                                      // Check for exact match
                                      if (
                                        p.resource === resource &&
                                        p.action === action
                                      ) {
                                        return true;
                                      }
                                      // Check for wildcard resource with exact action
                                      if (
                                        p.resource === "*" &&
                                        p.action === action
                                      ) {
                                        return true;
                                      }
                                      // Check for exact resource with wildcard action
                                      if (
                                        p.resource === resource &&
                                        p.action === "*"
                                      ) {
                                        return true;
                                      }
                                      // Check for wildcard resource with wildcard action
                                      if (
                                        p.resource === "*" &&
                                        p.action === "*"
                                      ) {
                                        return true;
                                      }
                                      return false;
                                    },
                                  );
                                  return (
                                    <label
                                      key={`${resource}-${action}`}
                                      className="flex items-center gap-2 cursor-pointer"
                                    >
                                      <input
                                        type="checkbox"
                                        checked={isChecked}
                                        onChange={(e) =>
                                          handlePermissionChange(
                                            resource,
                                            action,
                                            e.target.checked,
                                          )
                                        }
                                        className="w-4 h-4 text-[#112868] border-[rgba(0,0,0,0.2)] rounded focus:ring-[#112868]/20"
                                      />
                                      <span className="text-sm text-[#0e1b2a] capitalize">
                                        {action}
                                      </span>
                                    </label>
                                  );
                                })}
                              </div>
                            </div>
                          )}
                        </div>
                      );
                    },
                  )}
                </div>
              )}
            </div>
          </div>
        </form>
      )}
    </Modal>
  );
};
