import React, { useCallback, useMemo, useState } from 'react';
import { useTable } from '@refinedev/antd';
import { useGetLocale, useGetIdentity } from '@refinedev/core';
import { Table, Button, Space, Tooltip, message, Typography } from 'antd';

import { EditModal } from './Components/EditModal';
import { CreateModal } from './Components/CreateModal';
import type { RolePageTreeNode } from './types';
import { useRolePage } from './hooks/useRolePage';
import { EditOutlined, EyeOutlined, CodeOutlined } from '@ant-design/icons';
import { RoleDetailDrawer } from './Components/RoleDetailDrawer';
import { SqlModal, generateRoleSql } from '../../components/SqlModal';
import { customRequest } from '@/helpers/http';
import { buildPageTree } from '@/helpers/page-tree';

type RolePageInfo = {
  id: number;
  code: string;
  name: string;
  menuPath: string;
};

type RolePermissionSummary = {
  pageIds: number[];
  pageNames: string[];
  pageInfos: RolePageInfo[];
  actions: string[];
};

const PAGE_NAME_DISPLAY_LIMIT = 40;

const normalizeToNumber = (value: unknown): number | null => {
  if (typeof value === 'number' && !Number.isNaN(value)) {
    return value;
  }
  if (typeof value === 'string' && value.trim().length > 0) {
    const parsedValue = Number(value);
    return Number.isNaN(parsedValue) ? null : parsedValue;
  }
  return null;
};

const extractActionsFromRelation = (
  relation: any,
  pageRecord: any,
): string[] => {
  const aggregatedActions = new Set<string>();
  const relationActions = relation?.actions ?? relation?.actionList;

  if (Array.isArray(relationActions)) {
    relationActions.forEach((action: any) => {
      if (typeof action === 'string' && action) {
        aggregatedActions.add(action);
      } else if (typeof action === 'object' && action?.name) {
        aggregatedActions.add(action.name);
      }
    });
  } else if (typeof relationActions === 'string') {
    relationActions
      .split(',')
      .map((action: string) => action.trim())
      .filter(Boolean)
      .forEach((action) => aggregatedActions.add(action));
  }

  const pageResources =
    relation?.pageResources ??
    pageRecord?.pageResources ??
    pageRecord?.resources ??
    [];

  if (Array.isArray(pageResources)) {
    pageResources.forEach((resource: any) => {
      const action =
        resource?.action ?? resource?.code ?? resource?.name ?? resource;
      if (typeof action === 'string' && action) {
        aggregatedActions.add(action);
      }
    });
  }

  return Array.from(aggregatedActions);
};

export const RoleManagementListPage: React.FC = () => {
  const getLocale = useGetLocale();
  const currentLocale = getLocale();
  const { data: identity } = useGetIdentity<any>();

  const { tableProps } = useTable({
    resource: 'role',
    pagination: {
      pageSize: 20,
    },
  });

  const {
    rolePagesData,
    refetchRolePages,
    rolePagesQuery,
    pageData,
    refetchPages,
    pageQuery,
  } = useRolePage();

  const pageLookup = useMemo<Record<number, any>>(() => {
    const pages: any[] = Array.isArray(pageData?.data) ? pageData.data : [];
    const lookup: Record<number, any> = {};

    pages.forEach((page: any) => {
      const pageId = normalizeToNumber(
        page?.id ?? page?.pageId ?? page?.page_id,
      );
      if (pageId !== null) {
        lookup[pageId] = page;
      }
    });

    return lookup;
  }, [pageData]);

  const pageTreeData = useMemo<RolePageTreeNode[]>(() => {
    const pages: any[] = Array.isArray(pageData?.data) ? pageData.data : [];
    const isZh = currentLocale === 'zh_CN' || currentLocale === 'zh';
    return buildPageTree(pages, (page) =>
      isZh
        ? page?.zhName || page?.name || page?.code || `Page ${page.id}`
        : page?.enName || page?.name || page?.code || `Page ${page.id}`,
    ) as RolePageTreeNode[];
  }, [pageData, currentLocale]);

  const rolePermissionSummary = useMemo<
    Record<number, RolePermissionSummary>
  >(() => {
    const relations: any[] = Array.isArray(rolePagesData?.data)
      ? rolePagesData.data
      : [];
    const isZh = currentLocale === 'zh_CN' || currentLocale === 'zh';

    const getLocalizedName = (pageRecord: any, fallback: string): string => {
      if (isZh) {
        return (
          pageRecord?.zhName || pageRecord?.name || pageRecord?.code || fallback
        );
      }
      return (
        pageRecord?.enName || pageRecord?.name || pageRecord?.code || fallback
      );
    };

    const buildMenuPath = (pageId: number): string => {
      const parts: string[] = [];
      let currentId: number | null = pageId;
      const visited = new Set<number>();
      while (currentId !== null && !visited.has(currentId)) {
        visited.add(currentId);
        const record: any = pageLookup[currentId];
        if (!record) break;
        parts.unshift(
          getLocalizedName(record, record?.name || `Page ${currentId}`),
        );
        currentId =
          normalizeToNumber(record?.parentId ?? record?.parent_id) ?? null;
      }
      return parts.join(' / ');
    };

    const summaryMap: Record<number, RolePermissionSummary> = {};

    relations.forEach((relation: any) => {
      const roleId = normalizeToNumber(relation?.roleId);
      const pageId = normalizeToNumber(relation?.pageId);

      if (roleId === null || pageId === null) {
        return;
      }

      if (!summaryMap[roleId]) {
        summaryMap[roleId] = {
          pageIds: [],
          pageNames: [],
          pageInfos: [],
          actions: [],
        };
      }

      const summary = summaryMap[roleId];

      if (!summary.pageIds.includes(pageId)) {
        summary.pageIds.push(pageId);
      }

      const pageRecord = relation?.page ?? pageLookup[pageId];
      const pageName = pageRecord?.name || pageRecord?.code || `Page ${pageId}`;

      if (pageName && !summary.pageNames.includes(pageName)) {
        summary.pageNames.push(pageName);
      }

      const localizedName = getLocalizedName(pageRecord, pageName);
      if (!summary.pageInfos.some((p) => p.id === pageId)) {
        summary.pageInfos.push({
          id: pageId,
          code: pageRecord?.code ?? '',
          name: localizedName,
          menuPath: buildMenuPath(pageId),
        });
      }

      extractActionsFromRelation(relation, pageRecord).forEach((action) => {
        if (action && !summary.actions.includes(action)) {
          summary.actions.push(action);
        }
      });
    });

    // Build ancestor sort-order chain for hierarchical sorting
    const getSortChain = (pageId: number): number[] => {
      const chain: number[] = [];
      let currentId: number | null = pageId;
      const visited = new Set<number>();
      while (currentId !== null && !visited.has(currentId)) {
        visited.add(currentId);
        const record: any = pageLookup[currentId];
        if (!record) break;
        chain.unshift(record?.sortOrder ?? record?.sort_order ?? Infinity);
        currentId =
          normalizeToNumber(record?.parentId ?? record?.parent_id) ?? null;
      }
      return chain;
    };

    // Sort pageInfos by full ancestor sort-order chain
    Object.values(summaryMap).forEach((summary) => {
      summary.pageInfos.sort((a, b) => {
        const chainA = getSortChain(a.id);
        const chainB = getSortChain(b.id);
        const len = Math.max(chainA.length, chainB.length);
        for (let i = 0; i < len; i++) {
          const valA = chainA[i] ?? Infinity;
          const valB = chainB[i] ?? Infinity;
          if (valA !== valB) return valA - valB;
        }
        return chainA.length - chainB.length;
      });
    });

    return summaryMap;
  }, [rolePagesData, pageLookup, currentLocale]);

  const [drawerRole, setDrawerRole] = useState<any>(null);

  const [showModal, setShowModal] = useState<{
    type: 'show' | 'edit' | 'create' | null;
    id: number | null;
  }>({
    type: null,
    id: null,
  });

  const [sqlModal, setSqlModal] = useState<{
    open: boolean;
    title: string;
    sql: string;
  }>({ open: false, title: '', sql: '' });

  const handleShowSql = useCallback(
    async (record: any) => {
      const summary = rolePermissionSummary[record.id];
      const rolePages =
        summary?.pageInfos?.map((p) => ({
          pageId: p.id,
          pageCode: p.code,
          pageName: p.name,
        })) ?? [];

      let roleResources: Array<{
        resourceCode: string;
        resourceName: string;
        actions: string[];
      }> = [];
      try {
        const resp: any = await customRequest('roleResource/findMany', 'post', {
          where: { roleId: record.id },
          include: { resource: true },
        });
        const items: any[] = Array.isArray(resp?.data) ? resp.data : [];
        roleResources = items.map((item) => ({
          resourceCode: item.resource?.code ?? String(item.resourceId),
          resourceName: item.resource?.name ?? String(item.resourceId),
          actions: Array.isArray(item.actions) ? item.actions : [],
        }));
      } catch {
        message.warning(
          'Could not fetch role resource details; SQL will omit permissions.',
        );
      }

      const sql = generateRoleSql(record, rolePages, roleResources, {
        authorId: identity?.userid,
        authorName: identity?.username,
      });
      setSqlModal({ open: true, title: `SQL — Role: ${record.name}`, sql });
    },
    [rolePermissionSummary],
  );

  const refreshRoleRelatedData = useCallback(() => {
    refetchRolePages(rolePagesQuery ?? {});
    refetchPages(pageQuery ?? {});
  }, [refetchRolePages, rolePagesQuery, refetchPages, pageQuery]);

  const handleModalClose = useCallback(() => {
    setShowModal({ type: null, id: null });
  }, []);

  const handleModalSuccess = useCallback(() => {
    handleModalClose();
    refreshRoleRelatedData();
  }, [refreshRoleRelatedData, handleModalClose]);

  return (
    <div>
      <div
        style={{
          display: 'flex',
          justifyContent: 'space-between',
          alignItems: 'center',
          marginBottom: 16,
        }}
      >
        <Typography.Title level={4} style={{ margin: 0 }}>
          Role mgnts
        </Typography.Title>
        <Button
          type="primary"
          onClick={() =>
            setShowModal({
              type: 'create',
              id: null,
            })
          }
        >
          Create Role
        </Button>
      </div>
      <Table {...tableProps} rowKey="id">
        <Table.Column dataIndex="name" title="Name" />
        <Table.Column dataIndex="description" title="Description" />
        <Table.Column dataIndex="creator" title="Creator" />
        <Table.Column
          title="Actions"
          render={(_, record: any) => (
            <Space>
              <Tooltip title="View details">
                <Button
                  type="default"
                  size="small"
                  icon={<EyeOutlined />}
                  onClick={() => setDrawerRole(record)}
                />
              </Tooltip>
              <Tooltip title="Edit">
                <Button
                  type="default"
                  size="small"
                  icon={<EditOutlined />}
                  onClick={() => setShowModal({ type: 'edit', id: record.id })}
                />
              </Tooltip>
              <Tooltip title="Generate SQL">
                <Button
                  type="default"
                  size="small"
                  icon={<CodeOutlined />}
                  onClick={() => handleShowSql(record)}
                />
              </Tooltip>
            </Space>
          )}
        />
      </Table>
      {drawerRole && (
        <RoleDetailDrawer
          role={drawerRole}
          pages={rolePermissionSummary[drawerRole.id]?.pageInfos ?? []}
          open={!!drawerRole}
          onClose={() => setDrawerRole(null)}
        />
      )}
      {showModal.type === 'edit' && showModal.id && (
        <EditModal
          id={showModal.id}
          onClose={handleModalClose}
          onSuccess={handleModalSuccess}
          pageTreeData={pageTreeData}
          rolePermissionSummary={rolePermissionSummary[showModal.id]}
        />
      )}
      {showModal.type === 'create' && (
        <CreateModal
          onClose={handleModalClose}
          onSuccess={handleModalSuccess}
          pageTreeData={pageTreeData}
        />
      )}
      <SqlModal
        open={sqlModal.open}
        onClose={() => setSqlModal({ open: false, title: '', sql: '' })}
        title={sqlModal.title}
        sql={sqlModal.sql}
      />
    </div>
  );
};
