import React, { useEffect, useMemo, useState } from 'react';
import type {
  PageMenuTreeNode,
  PageResourceAssignment,
  ResourceDefinition,
} from '../types';
import { useModalForm } from '@refinedev/antd';
import { type HttpError, type RedirectAction } from '@refinedev/core';
import {
  Form,
  Input,
  Modal,
  Space,
  Tag,
  TreeSelect,
  Typography,
  Transfer,
  Checkbox,
  Table,
  Divider,
} from 'antd';
import type { TransferProps } from 'antd';
import { PageFieldSelector } from '../queries';

type PageFormFieldValues = {
  name?: string;
  zhName?: string;
  enName?: string;
  code?: string;
  path?: string | null;
  isVirtual?: boolean;
  parentId?: number | null;
  description?: string;
  iframeUrl?: string;
  externalRedirectUrl?: string;
  selectedResourceIds?: number[];
  resourcePermissionAssignments?: Record<number, string[]>;
};

const AVAILABLE_PERMISSION_ACTIONS = [
  'readAny',
  'createAny',
  'updateAny',
  'deleteAny',
];

const SPECIAL_CHARACTER_VALIDATION_PATTERN = /[^\u4e00-\u9fa5a-zA-Z0-9\s\-_/]/;

interface PageFormModalProps {
  formActionType: 'create' | 'edit';
  editingPageId?: number;
  redirectAfterSubmit?: RedirectAction;
  onFormSubmitSuccess?: () => void;
  onModalCancel?: () => void;
  parentPageTreeOptions?: PageMenuTreeNode[];
  allAvailableResources?: ResourceDefinition[];
  currentResourceAssignments?: PageResourceAssignment[];
  allPagesData?: any[]; // All pages data for duplication check
  defaultParentId?: number | null; // Default parent ID for create mode
  defaultPathPrefix?: string; // Default path prefix for create mode
}

const buildPageTreeNodeLookupMap = (
  treeNodes?: PageMenuTreeNode[],
): Map<string, PageMenuTreeNode> => {
  const nodeLookupMap = new Map<string, PageMenuTreeNode>();

  const traverseAndAddToMap = (nodes?: PageMenuTreeNode[]) => {
    nodes?.forEach((node) => {
      nodeLookupMap.set(String(node.value), node);
      if (node.children?.length) {
        traverseAndAddToMap(node.children);
      }
    });
  };

  traverseAndAddToMap(treeNodes);
  return nodeLookupMap;
};

export const PageFormModal: React.FC<PageFormModalProps> = ({
  formActionType,
  editingPageId,
  redirectAfterSubmit,
  onModalCancel,
  onFormSubmitSuccess,
  parentPageTreeOptions,
  allAvailableResources = [],
  currentResourceAssignments = [],
  allPagesData = [],
  defaultParentId,
  defaultPathPrefix = '',
}) => {
  const { formProps, modalProps, onFinish, close } = useModalForm<
    any,
    HttpError,
    PageFormFieldValues
  >({
    resource: 'page',
    action: formActionType,
    id: editingPageId,
    defaultVisible: true,
    redirect: redirectAfterSubmit,
    onMutationSuccess: () => {
      onFormSubmitSuccess?.();
    },
    meta: {
      select: PageFieldSelector,
    },
  });

  // Watch form values for conditional field visibility
  const isVirtual = Form.useWatch('isVirtual', formProps.form);
  const iframeUrl = Form.useWatch('iframeUrl', formProps.form);
  const externalRedirectUrl = Form.useWatch(
    'externalRedirectUrl',
    formProps.form,
  );
  const hasExternalUrl = !!(
    (iframeUrl && /^(https?:\/\/|\/\w)/.test(iframeUrl.trim())) ||
    (externalRedirectUrl && /^https?:\/\//.test(externalRedirectUrl.trim()))
  );

  const [selectedResourceIds, setSelectedResourceIds] = useState<string[]>([]);
  const [resourcePermissionMap, setResourcePermissionMap] = useState<
    Record<number, string[]>
  >({});
  const [permissionValidationError, setPermissionValidationError] =
    useState<string>('');
  const [initialResourceAssignments, setInitialResourceAssignments] = useState<{
    resourceIds: string[];
    permissionMap: Record<number, string[]>;
  }>({ resourceIds: [], permissionMap: {} });
  const [initialFormValues, setInitialFormValues] =
    useState<PageFormFieldValues>({});
  const [isCodeManuallyEdited, setIsCodeManuallyEdited] = useState(false);
  const [isPathManuallyEdited, setIsPathManuallyEdited] = useState(false);

  // Set default values for create mode with parent
  useEffect(() => {
    if (formActionType === 'create' && formProps.form) {
      const initialValues: Partial<PageFormFieldValues> = {};

      if (defaultParentId) {
        initialValues.parentId = defaultParentId;
      }
      if (defaultPathPrefix) {
        initialValues.path = defaultPathPrefix;
      }

      if (Object.keys(initialValues).length > 0) {
        formProps.form.setFieldsValue(initialValues);
      }
    }
  }, [formActionType, defaultParentId, defaultPathPrefix, formProps.form]);

  useEffect(() => {
    if (formActionType === 'edit' && currentResourceAssignments.length > 0) {
      const initialSelectedIds = currentResourceAssignments.map((assignment) =>
        String(assignment.resourceId),
      );
      setSelectedResourceIds(initialSelectedIds);

      const initialPermissionMap: Record<number, string[]> = {};
      currentResourceAssignments.forEach((assignment) => {
        initialPermissionMap[assignment.resourceId] = [
          ...assignment.assignedPermissions,
        ];
      });
      setResourcePermissionMap(initialPermissionMap);

      // Store initial state for comparison
      setInitialResourceAssignments({
        resourceIds: [...initialSelectedIds],
        permissionMap: JSON.parse(JSON.stringify(initialPermissionMap)),
      });
    }
  }, [formActionType, currentResourceAssignments]);

  // Store initial form values when form is loaded in edit mode
  useEffect(() => {
    if (formActionType === 'edit' && formProps.form) {
      const currentValues = formProps.form.getFieldsValue();
      setInitialFormValues({
        name: currentValues.name,
        zhName: currentValues.zhName,
        enName: currentValues.enName,
        code: currentValues.code,
        path: currentValues.path,
        isVirtual: currentValues.isVirtual,
        parentId: currentValues.parentId,
        description: currentValues.description,
        iframeUrl: currentValues.iframeUrl,
        externalRedirectUrl: currentValues.externalRedirectUrl,
      });
    }
  }, [formActionType, formProps.form, formProps.initialValues]);

  const resourceTransferDataSource = useMemo(() => {
    return allAvailableResources.map((resource) => ({
      key: String(resource.id),
      title: resource.name,
      description: resource.description || '',
    }));
  }, [allAvailableResources]);

  const handleResourceTransferChange: TransferProps['onChange'] = (
    newTargetKeys,
  ) => {
    setSelectedResourceIds(newTargetKeys as string[]);

    const newResourceIds = new Set(newTargetKeys.map((key) => Number(key)));
    setResourcePermissionMap((prevMap) => {
      const updatedMap: Record<number, string[]> = {};
      Object.keys(prevMap).forEach((resourceIdStr) => {
        const resourceId = Number(resourceIdStr);
        if (newResourceIds.has(resourceId)) {
          updatedMap[resourceId] = prevMap[resourceId];
        }
      });
      newTargetKeys.forEach((key) => {
        const resourceId = Number(key);
        if (!updatedMap[resourceId]) {
          updatedMap[resourceId] = []; // Initialize with empty array, user must select at least one permission
        }
      });
      return updatedMap;
    });

    // Clear validation error when user changes resource selection
    if (permissionValidationError) {
      setPermissionValidationError('');
    }
  };

  const handleResourcePermissionChange = (
    resourceId: number,
    permissionAction: string,
    isChecked: boolean,
  ) => {
    setResourcePermissionMap((prevMap) => {
      const currentPermissions = prevMap[resourceId] || [];
      let updatedPermissions: string[];

      if (isChecked) {
        updatedPermissions = [...currentPermissions, permissionAction];
      } else {
        updatedPermissions = currentPermissions.filter(
          (action) => action !== permissionAction,
        );
      }

      return {
        ...prevMap,
        [resourceId]: updatedPermissions,
      };
    });

    // Clear validation error when user makes changes
    if (permissionValidationError) {
      setPermissionValidationError('');
    }
  };

  const filteredParentPageTreeOptions = useMemo(() => {
    if (formActionType !== 'edit' || !editingPageId || !parentPageTreeOptions) {
      return parentPageTreeOptions;
    }

    const filterOutCurrentPage = (
      nodes: PageMenuTreeNode[],
    ): PageMenuTreeNode[] => {
      return nodes
        .filter((node) => String(node.value) !== String(editingPageId))
        .map((node) => ({
          ...node,
          children: node.children
            ? filterOutCurrentPage(node.children)
            : undefined,
        }));
    };

    return filterOutCurrentPage(parentPageTreeOptions);
  }, [parentPageTreeOptions, formActionType, editingPageId]);

  formProps.onFinish = (values) => {
    // Clear path when external URL is configured (iframe or redirect)
    if (!hasExternalUrl) {
      values.path = null;
    }

    // Validate that each selected resource has at least one permission
    const resourcesWithoutPermissions: string[] = [];
    selectedResourceIds.forEach((resourceIdStr) => {
      const resourceId = Number(resourceIdStr);
      const permissions = resourcePermissionMap[resourceId] || [];
      if (permissions.length === 0) {
        const resource = allAvailableResources.find((r) => r.id === resourceId);
        resourcesWithoutPermissions.push(
          resource?.name || `Resource ${resourceId}`,
        );
      }
    });

    if (resourcesWithoutPermissions.length > 0) {
      setPermissionValidationError(
        `The following resources must have at least one permission selected: ${resourcesWithoutPermissions.join(', ')}`,
      );
      return;
    }

    // In edit mode, check if anything has changed
    if (formActionType === 'edit') {
      // Check if form fields have changed
      const formFieldsChanged =
        values.name !== initialFormValues.name ||
        values.zhName !== initialFormValues.zhName ||
        values.enName !== initialFormValues.enName ||
        values.code !== initialFormValues.code ||
        values.path !== initialFormValues.path ||
        values.description !== initialFormValues.description ||
        values.isVirtual !== initialFormValues.isVirtual ||
        values.parentId !== initialFormValues.parentId ||
        values.iframeUrl !== initialFormValues.iframeUrl ||
        values.externalRedirectUrl !== initialFormValues.externalRedirectUrl;

      // Check if resource assignments have changed
      const resourceIdsChanged =
        selectedResourceIds.length !==
          initialResourceAssignments.resourceIds.length ||
        selectedResourceIds.some(
          (id) => !initialResourceAssignments.resourceIds.includes(id),
        );

      let permissionsChanged = false;
      if (!resourceIdsChanged) {
        // Check if permissions for any resource have changed
        for (const resourceIdStr of selectedResourceIds) {
          const resourceId = Number(resourceIdStr);
          const currentPermissions = resourcePermissionMap[resourceId] || [];
          const initialPermissions =
            initialResourceAssignments.permissionMap[resourceId] || [];

          if (
            currentPermissions.length !== initialPermissions.length ||
            currentPermissions.some((p) => !initialPermissions.includes(p))
          ) {
            permissionsChanged = true;
            break;
          }
        }
      }

      // If nothing has changed, don't submit
      if (!formFieldsChanged && !resourceIdsChanged && !permissionsChanged) {
        Modal.info({
          title: 'No Changes Detected',
          content:
            'No changes have been made to the form. The form will be closed without submitting.',
        });
        close();
        return;
      }

      // Build the submit payload with only changed data
      const formattedValuesForSubmit: any = {
        ...values,
        parentId: values.parentId ? Number(values.parentId) : null,
      };

      // Only include resourceAssignments if they changed
      if (resourceIdsChanged || permissionsChanged) {
        formattedValuesForSubmit.resourceAssignments = selectedResourceIds.map(
          (resourceIdStr) => {
            const resourceId = Number(resourceIdStr);
            const resource = allAvailableResources.find(
              (r) => r.id === resourceId,
            );
            return {
              resourceId,
              resourceName: resource?.name || '',
              assignedPermissions: resourcePermissionMap[resourceId] || [],
            };
          },
        );
      }
      onFinish(formattedValuesForSubmit);
    } else {
      // In create mode, always submit all data
      const resourceAssignmentsForSubmit = selectedResourceIds.map(
        (resourceIdStr) => {
          const resourceId = Number(resourceIdStr);
          const resource = allAvailableResources.find(
            (r) => r.id === resourceId,
          );
          return {
            resourceId,
            resourceName: resource?.name || '',
            assignedPermissions: resourcePermissionMap[resourceId] || [],
          };
        },
      );

      const formattedValuesForSubmit = {
        ...values,
        parentId: values.parentId ? Number(values.parentId) : null,
        resourceAssignments: resourceAssignmentsForSubmit,
      };

      onFinish(formattedValuesForSubmit);
    }
  };

  const resourcePermissionTableColumns = [
    {
      title: 'Resource Name',
      dataIndex: 'resourceName',
      key: 'resourceName',
      width: '30%',
    },
    {
      title: 'Permissions',
      key: 'permissions',
      render: (
        _: any,
        record: { resourceId: number; resourceName: string },
      ) => (
        <Space>
          {AVAILABLE_PERMISSION_ACTIONS.map((permissionAction) => (
            <Checkbox
              key={`${record.resourceId}-${permissionAction}`}
              checked={resourcePermissionMap[record.resourceId]?.includes(
                permissionAction,
              )}
              onChange={(e) =>
                handleResourcePermissionChange(
                  record.resourceId,
                  permissionAction,
                  e.target.checked,
                )
              }
            >
              {permissionAction}
            </Checkbox>
          ))}
        </Space>
      ),
    },
  ];

  const selectedResourcesForPermissionTable = useMemo(() => {
    return selectedResourceIds.map((resourceIdStr) => {
      const resourceId = Number(resourceIdStr);
      const resource = allAvailableResources.find((r) => r.id === resourceId);
      return {
        resourceId,
        resourceName: resource?.name || `Resource ${resourceId}`,
      };
    });
  }, [selectedResourceIds, allAvailableResources]);

  return (
    <Modal
      {...modalProps}
      width={800}
      onCancel={() => {
        if (onModalCancel) {
          onModalCancel();
          return;
        }
        close();
      }}
      title={formActionType === 'create' ? 'Create New Page' : 'Edit Page'}
    >
      <Form {...formProps} layout="vertical">
        <Form.Item
          rules={[
            { required: true, message: 'Page name is required' },
            {
              validator: (_, value) => {
                if (
                  !value ||
                  !SPECIAL_CHARACTER_VALIDATION_PATTERN.test(value)
                ) {
                  return Promise.resolve();
                }
                return Promise.reject(
                  new Error('Special characters are not allowed in page name.'),
                );
              },
            },
            {
              validator: async (_, value) => {
                if (!value) {
                  return Promise.resolve();
                }

                const trimmedValue = value.trim();

                // Check if page name already exists (case-insensitive)
                const isDuplicate = allPagesData.some((page: any) => {
                  // Skip current page when editing
                  if (formActionType === 'edit' && page.id === editingPageId) {
                    return false;
                  }
                  return (
                    page.name?.toLowerCase() === trimmedValue.toLowerCase()
                  );
                });

                if (isDuplicate) {
                  return Promise.reject(
                    new Error(
                      "⚠️ Warning: Page Name already exists. It's recommended to use a unique name.",
                    ),
                  );
                }

                return Promise.resolve();
              },
            },
          ]}
          name="name"
          label="Page Name"
        >
          <Input
            placeholder="Enter the page name (e.g., User Management)."
            onChange={(e) => {
              const nameValue = e.target.value;
              // Auto-generate code from name if code hasn't been manually edited
              if (!isCodeManuallyEdited && nameValue) {
                const generatedCode = nameValue
                  .trim()
                  .toLowerCase()
                  .replace(/[\s-]+/g, '_') // Replace spaces and hyphens with underscores
                  .replace(/[^a-z0-9_]/g, ''); // Remove invalid characters
                formProps.form?.setFieldsValue({ code: generatedCode });
              }
              // Auto-generate path from name if path hasn't been manually edited (only in create mode)
              if (
                !isPathManuallyEdited &&
                nameValue &&
                formActionType === 'create'
              ) {
                const generatedPathSegment = nameValue
                  .trim()
                  .toLowerCase()
                  .replace(/[\s_]+/g, '-') // Replace spaces and underscores with hyphens
                  .replace(/[^a-z0-9-/]/g, ''); // Remove invalid characters
                const newPath = defaultPathPrefix + generatedPathSegment;
                formProps.form?.setFieldsValue({ path: newPath });
              }
            }}
          />
        </Form.Item>
        <Form.Item
          rules={[
            { required: true, message: 'Page Code is required' },
            {
              pattern: /^[a-zA-Z0-9_]+$/,
              message:
                'Page Code can only contain letters, numbers and underscores',
            },
            {
              validator: async (_, value) => {
                if (!value) {
                  return Promise.resolve();
                }

                const trimmedValue = value.trim();

                // Check if page code already exists (case-insensitive)
                const isDuplicate = allPagesData.some((page: any) => {
                  // Skip current page when editing
                  if (formActionType === 'edit' && page.id === editingPageId) {
                    return false;
                  }
                  return (
                    page.code?.toLowerCase() === trimmedValue.toLowerCase()
                  );
                });

                if (isDuplicate) {
                  return Promise.reject(
                    new Error(
                      'Page Code already exists. Please use a different code.',
                    ),
                  );
                }

                return Promise.resolve();
              },
            },
          ]}
          name="code"
          label="Page Code(建议使用根据Page Name自动生成的值。一旦保存，不建议修改，因为前端会使用它作为菜单标识)"
        >
          <Input
            placeholder="Enter the page code (e.g., user_management)"
            onChange={() => {
              // Mark as manually edited when user types in this field
              if (!isCodeManuallyEdited) {
                setIsCodeManuallyEdited(true);
              }
            }}
          />
        </Form.Item>
        <Form.Item name="isVirtual" valuePropName="checked">
          <Checkbox>Is Virtual Page</Checkbox>
        </Form.Item>
        {!isVirtual && (
          <>
            <Form.Item name="parentId" label="Parent Page (Menu Position)">
              {filteredParentPageTreeOptions?.length ? (
                <TreeSelect
                  style={{ width: '100%' }}
                  treeData={filteredParentPageTreeOptions}
                  treeDefaultExpandAll
                  allowClear
                  placeholder="Select parent page (leave empty for root level)"
                />
              ) : (
                <>
                  <Typography.Text type="secondary">
                    No parent pages available. This page will be created at root
                    level.
                  </Typography.Text>
                  <Input type="hidden" />
                </>
              )}
            </Form.Item>
            <Form.Item
              name="zhName"
              label="Chinese Name (中文菜单名)"
              tooltip="用于菜单显示的中文名称"
            >
              <Input placeholder="输入中文菜单名 (例如: 用户管理)" />
            </Form.Item>
            <Form.Item
              name="enName"
              label="English Name (英文菜单名)"
              tooltip="Menu display name in English"
            >
              <Input placeholder="Enter English menu name (e.g., User Management)" />
            </Form.Item>
            <Form.Item
              name="iframeUrl"
              label={'Iframe URL'}
              tooltip={{
                title: (
                  <div>
                    <p style={{ marginBottom: 8 }}>
                      设置后，页面将以 iframe 形式加载该 URL，而非内部组件渲染。
                    </p>
                    <p style={{ marginBottom: 4 }}>
                      <strong>支持的模板变量：</strong>
                    </p>
                    <ul style={{ margin: 0, paddingLeft: 16 }}>
                      <li>
                        <code>{'{{locale}}'}</code> → 当前语言 (en/zh_CN)
                      </li>
                    </ul>
                    <p style={{ marginTop: 8 }}>
                      支持完整 URL 或相对路径（如 /path/to/page）
                    </p>
                  </div>
                ),
                overlayStyle: { maxWidth: 320 },
              }}
              dependencies={['externalRedirectUrl']}
              rules={[
                {
                  validator: (_, value) => {
                    if (value?.trim() && externalRedirectUrl?.trim()) {
                      return Promise.reject(
                        new Error(
                          '不能同时填写 Iframe URL 和 External Redirect URL，请只填其中一个',
                        ),
                      );
                    }
                    return Promise.resolve();
                  },
                },
              ]}
            >
              <Input placeholder="e.g. https://example.com/page or /relative/path" />
            </Form.Item>
            <Form.Item
              name="externalRedirectUrl"
              dependencies={['iframeUrl']}
              label={'External Redirect URL'}
              tooltip={{
                title: (
                  <p style={{ marginBottom: 8 }}>
                    设置后，页面将打开一个新标签并跳转到指定的外部链接。
                  </p>
                ),
                overlayStyle: { maxWidth: 320 },
              }}
              rules={[
                {
                  type: 'url',
                  message: 'Please enter a valid URL',
                },
                {
                  validator: (_, value) => {
                    if (value?.trim() && iframeUrl?.trim()) {
                      return Promise.reject(
                        new Error(
                          '不能同时填写 Iframe URL 和 External Redirect URL，请只填其中一个',
                        ),
                      );
                    }
                    return Promise.resolve();
                  },
                },
              ]}
            >
              <Input placeholder="e.g. https://oit-erp.woa.com" />
            </Form.Item>
            {hasExternalUrl && (
              <Form.Item
                rules={[
                  {
                    validator: (_, value) => {
                      if (
                        !value ||
                        !SPECIAL_CHARACTER_VALIDATION_PATTERN.test(value)
                      ) {
                        return Promise.resolve();
                      }
                      return Promise.reject(
                        new Error(
                          'Special characters are not allowed in path.',
                        ),
                      );
                    },
                  },
                ]}
                name="path"
                label="Page Path"
                tooltip="仅当前端 routeRegistry 中未注册该 page code 时需要填写（如 iframe/外部链接页面）。前端已注册的页面会自动匹配路径，无需手动填写。"
              >
                <Input
                  placeholder="Enter the URL path (e.g., /administration/page-management)"
                  onChange={() => {
                    // Mark as manually edited when user types in this field
                    if (!isPathManuallyEdited) {
                      setIsPathManuallyEdited(true);
                    }
                  }}
                />
              </Form.Item>
            )}
          </>
        )}
        <Form.Item name="description" label="Page Description">
          <Input.TextArea
            rows={2}
            placeholder="Enter a brief description of this page's purpose"
          />
        </Form.Item>
        <Divider>Resource Assignment & Permissions</Divider>
        <Form.Item label="Select Resources to Assign">
          <Transfer
            dataSource={resourceTransferDataSource}
            titles={['Available Resources', 'Assigned Resources']}
            targetKeys={selectedResourceIds}
            onChange={handleResourceTransferChange}
            render={(item) => item.title}
            showSearch
            filterOption={(inputValue, item) =>
              item.title.toLowerCase().includes(inputValue.toLowerCase()) ||
              item.description.toLowerCase().includes(inputValue.toLowerCase())
            }
            listStyle={{ width: 280, height: 250 }}
          />
        </Form.Item>
        {selectedResourceIds.length > 0 && (
          <Form.Item
            label="Configure Permissions for Each Resource"
            validateStatus={permissionValidationError ? 'error' : ''}
            help={permissionValidationError || ''}
          >
            <Table
              dataSource={selectedResourcesForPermissionTable}
              columns={resourcePermissionTableColumns}
              rowKey="resourceId"
              pagination={false}
              size="small"
              bordered
            />
          </Form.Item>
        )}
        {formActionType === 'edit' && currentResourceAssignments.length > 0 && (
          <Form.Item label="Current Permission Overview">
            <Space wrap>
              {Array.from(
                new Set(
                  currentResourceAssignments.flatMap(
                    (a) => a.assignedPermissions,
                  ),
                ),
              ).map((permissionAction) => (
                <Tag key={permissionAction} color="blue">
                  {permissionAction}
                </Tag>
              ))}
            </Space>
          </Form.Item>
        )}
      </Form>
    </Modal>
  );
};
