import { Inject, Injectable } from '@nestjs/common';
import { Prisma, Role } from '@prisma/client';
import { WINSTON_MODULE_PROVIDER } from 'nest-winston';
import { PrismaService } from 'nestjs-prisma';
import { Logger } from 'winston';

import { RolesBuilder } from 'nest-access-control';
import { createSafeLogData } from '../../lib/safe-log.util';

@Injectable()
export class RoleService {
  // 单例 RolesBuilder 引用 — 其他代码通过 DI 或导出此实例读取
  private rolesBuilder: RolesBuilder = new RolesBuilder();

  constructor(
    private prisma: PrismaService,
    @Inject(WINSTON_MODULE_PROVIDER) private readonly logger: Logger,
  ) {}

  get rolesBuilderRef() {
    return this.rolesBuilder;
  }

  async getBuilder(): Promise<RolesBuilder> {
    // console.log('[__ROLE_PAGE_RESOURCE__] Getting roles from DB...');
    const newBuilder = new RolesBuilder();

    // 查询所有通用资源
    const commonResources = await this.prisma.resource.findMany({
      where: { isCommonResource: true },
      select: { id: true, name: true },
    });

    const rows = await this.prisma.role.findMany({
      include: {
        roleResources: {
          include: {
            resource: true,
          },
        },
      },
    });

    for (const role of rows) {
      const roleName = role.name;

      const grant = newBuilder.grant(roleName);

      // 记录该角色已配置的资源 ID，用于判断是否需要添加通用资源的默认权限
      const configuredResourceIds = new Set<number>();

      // 处理新的数据结构：通过 roleResources 关联表获取权限
      if (role.roleResources && role.roleResources.length > 0) {
        for (const roleResource of role.roleResources) {
          const resourceName = roleResource.resource?.name;
          const resourceId = roleResource.resource?.id;
          const actions = roleResource.actions;

          if (resourceId) {
            configuredResourceIds.add(resourceId);
          }

          if (resourceName && actions) {
            // actions 现在是 JsonValue 类型，需要处理
            let actionsArray: string[] = [];
            if (typeof actions === 'string') {
              actionsArray = actions.split(',');
            } else if (Array.isArray(actions)) {
              actionsArray = actions.map(String);
            } else if (actions && typeof actions === 'object') {
              // 如果是对象，尝试提取数组或转换为字符串数组
              actionsArray = Object.values(actions).map(String);
            }
            for (const action of actionsArray) {
              grant[action](resourceName, ['*']);
            }
          }
        }
      }

      // 为所有角色添加通用资源的 readAny 权限（如果该角色没有配置该资源）
      for (const commonResource of commonResources) {
        if (!configuredResourceIds.has(commonResource.id)) {
          grant.readAny(commonResource.name, ['*']);
        }
      }
    }

    this.rolesBuilder = newBuilder;
    // console.log(
    //   `[__ROLE_PAGE_RESOURCE__] Roles built successfully with ${commonResources.length} common resources.`,
    // );
    return newBuilder;
  }

  async createOne(roleCreateArgs: Prisma.RoleCreateArgs) {
    this.logger.info(
      '[Role] Creating role',
      createSafeLogData({
        operation: 'CREATE',
        table: 'role',
        data: roleCreateArgs.data,
      }),
    );
    const result = await this.prisma.role.create(roleCreateArgs);
    this.logger.info(
      '[Role] Role created successfully',
      createSafeLogData({
        operation: 'CREATE',
        table: 'role',
        result: result,
      }),
    );
    return result;
  }

  /**
   * 根据 pageIds 准备 roleResources 数据（从 pageResources 查询并合并 actions）
   * @param pageIds 页面 ID 数组
   * @returns roleResources 数据数组（不包含 roleId）
   */
  private async prepareRoleResourcesFromPages(
    pageIds: number[],
  ): Promise<Omit<Prisma.RoleResourceCreateManyInput, 'roleId'>[]> {
    if (!pageIds || pageIds.length === 0) {
      return [];
    }

    // 查询 pageResources 数据（在事务外查询是安全的，因为 pageResource 是相对静态的配置数据）
    const pageResources = await this.prisma.pageResource.findMany({
      where: {
        pageId: { in: pageIds },
      },
      select: {
        resourceId: true,
        actions: true,
      },
    });

    if (pageResources.length === 0) {
      return [];
    }

    // 合并 actions（同一个 resource 可能在多个 page 中，需要取并集）
    const resourceActionsMap = new Map<number, Set<string>>();

    for (const pr of pageResources) {
      const resourceId = pr.resourceId;
      let actionsSet = resourceActionsMap.get(resourceId);

      if (!actionsSet) {
        actionsSet = new Set<string>();
        resourceActionsMap.set(resourceId, actionsSet);
      }

      // 解析 actions（JSON 数组格式，如 ["readAny", "deleteAny"]）
      const actions = this.parseActions(pr.actions);
      actions.forEach((action) => actionsSet.add(action));
    }

    return Array.from(resourceActionsMap.entries()).map(
      ([resourceId, actionsSet]) => ({
        resourceId,
        actions: Array.from(actionsSet) as Prisma.InputJsonValue,
      }),
    );
  }

  /**
   * 同步角色的页面权限和资源权限（用于事务数组）
   * @param roleId 角色 ID
   * @param pageIds 页面 ID 数组
   * @param roleResourcesTemplate 资源权限模板数据（不包含 roleId）
   * @returns 事务操作数组
   */
  private async syncRolePagesAndResources(
    roleId: number,
    pageIds: number[],
    roleResourcesTemplate: Omit<Prisma.RoleResourceCreateManyInput, 'roleId'>[],
  ): Promise<any[]> {
    const operations: any[] = [];

    // 查询当前角色的旧页面权限
    const oldRolePages = await this.prisma.rolePages.findMany({
      where: { roleId },
      include: {
        page: {
          select: {
            id: true,
            name: true,
          },
        },
      },
    });

    // 查询当前角色的旧资源权限
    const oldRoleResources = await this.prisma.roleResource.findMany({
      where: { roleId },
      include: {
        resource: {
          select: {
            id: true,
            name: true,
            isCommonResource: true,
          },
        },
      },
    });

    const oldPageIds = oldRolePages.map((rp) => rp.pageId);
    const newPageIds = pageIds;

    // 计算页面变化
    const pagesToDelete = oldRolePages.filter(
      (rp) => !newPageIds.includes(rp.pageId),
    );
    const pagesToAdd = newPageIds.filter(
      (pageId) => !oldPageIds.includes(pageId),
    );

    // 计算资源变化
    const oldResourceMap = new Map(
      oldRoleResources.map((rr) => [
        rr.resourceId,
        {
          actions: rr.actions,
          resourceName: rr.resource.name,
        },
      ]),
    );

    const newResourceMap = new Map(
      roleResourcesTemplate.map((template) => [
        template.resourceId,
        {
          actions: template.actions,
        },
      ]),
    );

    // 查询所有「通过页面管理的资源」（即在 t_page_resource 中存在的资源）
    // 只有这类资源才应受页面变更影响；直接授权的资源（如 rolePages/roleResource/pageResource）
    // 没有 t_page_resource 记录，绝对不能被页面同步逻辑删除
    const allPageManagedResources = await this.prisma.pageResource.findMany({
      select: { resourceId: true },
      distinct: ['resourceId'],
    });
    const pageManagedResourceIds = new Set(
      allPageManagedResources.map((pr) => pr.resourceId),
    );

    // 只删除那些：1) 不在新资源列表中，且 2) 不是通用资源，且 3) 是页面管理的资源
    // 条件 3 确保直接授权的资源（没有任何 t_page_resource 记录）不会被误删
    const resourcesToDelete = oldRoleResources.filter(
      (rr) =>
        !newResourceMap.has(rr.resourceId) &&
        !rr.resource.isCommonResource &&
        pageManagedResourceIds.has(rr.resourceId),
    );

    const resourcesToAdd = roleResourcesTemplate.filter(
      (template) => !oldResourceMap.has(template.resourceId),
    );

    const resourcesToUpdate = roleResourcesTemplate.filter((template) => {
      const oldResource = oldResourceMap.get(template.resourceId);
      if (!oldResource) return false;
      // 比较 actions 是否有变化（排序后再比较，避免顺序不同导致误判）
      const oldActions = Array.isArray(oldResource.actions)
        ? [...(oldResource.actions as string[])].sort()
        : [];
      const newActions = Array.isArray(template.actions)
        ? [...(template.actions as string[])].sort()
        : [];
      return JSON.stringify(oldActions) !== JSON.stringify(newActions);
    });

    // 打印对比结果
    console.log(
      '\n[__ROLE_PAGE_RESOURCE__] ========== 角色权限变更对比 ==========',
    );
    console.log(`[__ROLE_PAGE_RESOURCE__] 角色 ID: ${roleId}`);
    console.log('[__ROLE_PAGE_RESOURCE__] 【页面权限变化】');
    console.log(
      `[__ROLE_PAGE_RESOURCE__] 删除的页面 (${pagesToDelete.length}):`,
    );
    pagesToDelete.forEach((rp) => {
      console.log(
        `[__ROLE_PAGE_RESOURCE__]   - [${rp.pageId}] ${rp.page.name}`,
      );
    });
    console.log(`[__ROLE_PAGE_RESOURCE__] 新增的页面 (${pagesToAdd.length}):`);
    for (const pageId of pagesToAdd) {
      const page = await this.prisma.page.findUnique({
        where: { id: pageId },
        select: { id: true, name: true },
      });
      if (page) {
        console.log(`[__ROLE_PAGE_RESOURCE__]   + [${page.id}] ${page.name}`);
      }
    }

    console.log('[__ROLE_PAGE_RESOURCE__] 【资源权限变化】');
    console.log(
      `[__ROLE_PAGE_RESOURCE__] 删除的资源 (${resourcesToDelete.length}):`,
    );
    resourcesToDelete.forEach((rr) => {
      console.log(
        `[__ROLE_PAGE_RESOURCE__]   - [${rr.resourceId}] ${
          rr.resource.name
        } - actions: ${JSON.stringify(rr.actions)}`,
      );
    });

    console.log(
      `[__ROLE_PAGE_RESOURCE__] 新增的资源 (${resourcesToAdd.length}):`,
    );
    for (const template of resourcesToAdd) {
      const resource = await this.prisma.resource.findUnique({
        where: { id: template.resourceId },
        select: { id: true, name: true },
      });
      if (resource) {
        console.log(
          `[__ROLE_PAGE_RESOURCE__]   + [${resource.id}] ${
            resource.name
          } - actions: ${JSON.stringify(template.actions)}`,
        );
      }
    }

    console.log(
      `[__ROLE_PAGE_RESOURCE__] 更新的资源 (${resourcesToUpdate.length}):`,
    );
    for (const template of resourcesToUpdate) {
      const resource = await this.prisma.resource.findUnique({
        where: { id: template.resourceId },
        select: { id: true, name: true },
      });
      const oldResource = oldResourceMap.get(template.resourceId);
      if (resource && oldResource) {
        console.log(
          `[__ROLE_PAGE_RESOURCE__]   ~ [${resource.id}] ${resource.name}`,
        );
        console.log(
          `[__ROLE_PAGE_RESOURCE__]     旧 actions: ${JSON.stringify(
            oldResource.actions,
          )}`,
        );
        console.log(
          `[__ROLE_PAGE_RESOURCE__]     新 actions: ${JSON.stringify(
            template.actions,
          )}`,
        );
      }
    }
    // 1. 增量更新 rolePages：只删除需要删除的，只添加需要添加的
    const pageIdsToDelete = pagesToDelete.map((rp) => rp.pageId);

    if (pageIdsToDelete.length > 0) {
      this.logger.info(
        '[RolePages] Deleting role pages',
        createSafeLogData({
          operation: 'DELETE_MANY',
          table: 'rolePages',
          roleId: roleId,
          pageIds: pageIdsToDelete,
        }),
      );
      operations.push(
        this.prisma.rolePages.deleteMany({
          where: {
            roleId,
            pageId: { in: pageIdsToDelete },
          },
        }),
      );
    }

    // 2. 如果有新的 pageIds，批量插入
    if (pagesToAdd.length > 0) {
      const rolePagesData = pagesToAdd.map((pageId) => ({
        roleId,
        pageId,
      }));

      this.logger.info(
        '[RolePages] Creating role pages',
        createSafeLogData({
          operation: 'CREATE_MANY',
          table: 'rolePages',
          roleId: roleId,
          data: rolePagesData,
        }),
      );
      operations.push(
        this.prisma.rolePages.createMany({
          data: rolePagesData,
          skipDuplicates: true,
        }),
      );
    }

    // 3. 只删除那些需要删除的资源（不是全部删除）
    if (resourcesToDelete.length > 0) {
      const resourceIdsToDelete = resourcesToDelete.map((rr) => rr.resourceId);
      this.logger.info(
        '[RoleResource] Deleting role resources',
        createSafeLogData({
          operation: 'DELETE_MANY',
          table: 'roleResource',
          roleId: roleId,
          resourceIds: resourceIdsToDelete,
          oldData: resourcesToDelete,
        }),
      );
      operations.push(
        this.prisma.roleResource.deleteMany({
          where: {
            roleId,
            resourceId: {
              in: resourceIdsToDelete,
            },
          },
        }),
      );
    }

    // 4. 插入新的资源权限
    if (resourcesToAdd.length > 0) {
      const roleResourcesData = resourcesToAdd.map((template) => ({
        ...template,
        roleId,
      }));

      this.logger.info(
        '[RoleResource] Creating role resources',
        createSafeLogData({
          operation: 'CREATE_MANY',
          table: 'roleResource',
          roleId: roleId,
          data: roleResourcesData,
        }),
      );
      operations.push(
        this.prisma.roleResource.createMany({
          data: roleResourcesData,
          skipDuplicates: true,
        }),
      );
    }

    // 5. 更新已存在但 actions 有变化的资源
    if (resourcesToUpdate.length > 0) {
      for (const template of resourcesToUpdate) {
        const oldResource = oldResourceMap.get(template.resourceId);
        this.logger.info(
          '[RoleResource] Updating role resource',
          createSafeLogData({
            operation: 'UPDATE_MANY',
            table: 'roleResource',
            roleId: roleId,
            resourceId: template.resourceId,
            oldActions: oldResource?.actions,
            newActions: template.actions,
          }),
        );
        operations.push(
          this.prisma.roleResource.updateMany({
            where: {
              roleId,
              resourceId: template.resourceId,
            },
            data: {
              actions: template.actions,
            },
          }),
        );
      }
    }

    return operations;
  }

  /**
   * 刷新指定角色的所有资源权限
   * 当页面的资源配置发生变化时，需要调用此方法重新计算角色的 RoleResource
   */
  async refreshRolePermissions(roleId: number) {
    // 1. 获取角色当前关联的所有页面
    const rolePages = await this.prisma.rolePages.findMany({
      where: { roleId },
      select: { pageId: true },
    });
    const pageIds = rolePages.map((rp) => rp.pageId);

    // 2. 根据页面重新计算资源权限模板
    const roleResourcesTemplate =
      pageIds.length > 0
        ? await this.prepareRoleResourcesFromPages(pageIds)
        : [];

    // 3. 生成同步操作
    const operations = await this.syncRolePagesAndResources(
      roleId,
      pageIds,
      roleResourcesTemplate,
    );

    // 4. 执行事务
    if (operations.length > 0) {
      this.logger.info(
        `[RoleService] Refreshing permissions for role ${roleId}`,
      );
      await this.prisma.$transaction(operations);
    }
  }

  /**
   * 刷新所有关联了指定页面的角色的权限
   * 当页面资源发生变更（新增/修改/删除）时调用
   */
  async refreshRolesWithPage(pageId: number) {
    const rolePages = await this.prisma.rolePages.findMany({
      where: { pageId },
      select: { roleId: true },
    });

    this.logger.info(
      `[RoleService] Found ${rolePages.length} roles associated with page ${pageId}, starting refresh...`,
    );

    for (const rp of rolePages) {
      await this.refreshRolePermissions(rp.roleId);
    }
  }

  /**
   * 在事务中创建角色及其页面权限，确保原子性
   * @param roleData 角色创建数据
   * @param pageIds 页面 ID 数组（可选）
   */
  async createRoleWithPages(
    roleData: Prisma.RoleCreateInput,
    pageIds?: number[],
  ) {
    // 先准备 roleResources 数据模板
    const roleResourcesTemplate =
      pageIds && pageIds.length > 0
        ? await this.prepareRoleResourcesFromPages(pageIds)
        : [];

    // 使用 Prisma 的嵌套创建语法，一次性完成所有操作
    // 这样可以使用事务数组形式而非回调形式
    const createData: Prisma.RoleCreateInput = {
      ...roleData,
    };

    // 如果有 pageIds，添加嵌套创建
    if (pageIds && pageIds.length > 0) {
      createData.rolePages = {
        create: pageIds.map((pageId) => ({ pageId })),
      };

      if (roleResourcesTemplate.length > 0) {
        createData.roleResources = {
          create: roleResourcesTemplate.map((template) => ({
            resourceId: template.resourceId,
            actions: template.actions,
          })),
        };
      }
    }

    // 使用事务数组形式（而非回调形式）
    this.logger.info(
      '[Role] Creating role with pages in transaction',
      createSafeLogData({
        operation: 'CREATE_WITH_PAGES',
        table: 'role',
        roleData: roleData,
        pageIds: pageIds,
        roleResourcesTemplate: roleResourcesTemplate,
      }),
    );
    const operations = [
      this.prisma.role.create({
        data: createData,
      }),
    ];

    const results = await this.prisma.$transaction(operations);
    this.logger.info(
      '[Role] Role with pages created successfully',
      createSafeLogData({
        operation: 'CREATE_WITH_PAGES',
        table: 'role',
        result: results[0],
      }),
    );
    return results[0];
  }

  /**
   * 解析 actions 字段（支持多种格式）
   * JSON 数组格式如: ["readAny", "deleteAny"]
   */
  private parseActions(actions: any): string[] {
    if (!actions) return [];

    // 如果已经是数组，直接返回
    if (Array.isArray(actions)) {
      return actions.map(String).filter(Boolean);
    }

    // 如果是字符串，尝试解析为 JSON
    if (typeof actions === 'string') {
      try {
        const parsed = JSON.parse(actions);
        if (Array.isArray(parsed)) {
          return parsed.map(String).filter(Boolean);
        }
        // 如果不是数组，按逗号分隔
        return actions
          .split(',')
          .map((s) => s.trim())
          .filter(Boolean);
      } catch {
        // JSON 解析失败，按逗号分隔
        return actions
          .split(',')
          .map((s) => s.trim())
          .filter(Boolean);
      }
    }

    return [];
  }

  async createMany(data: Prisma.RoleCreateManyArgs['data']) {
    this.logger.info(
      '[Role] Creating multiple roles',
      createSafeLogData({
        operation: 'CREATE_MANY',
        table: 'role',
        count: Array.isArray(data) ? data.length : 1,
        data: data,
      }),
    );
    const result = await this.prisma.role.createMany({
      data,
      skipDuplicates: true,
    });
    this.logger.info(
      '[Role] Multiple roles created successfully',
      createSafeLogData({
        operation: 'CREATE_MANY',
        table: 'role',
        count: result.count,
      }),
    );
    return result;
  }

  async findMany(
    roleFindManyArgs: Prisma.RoleFindManyArgs,
  ): Promise<{ itemCount: number; entities: Role[] }> {
    const itemCount = await this.prisma.role.count({
      where: roleFindManyArgs.where,
    });
    const entities = await this.prisma.role.findMany(roleFindManyArgs);
    return { itemCount, entities };
  }

  async findUnique(id: number, select: Prisma.RoleFindUniqueArgs['select']) {
    return await this.prisma.role.findUnique({
      where: { id: id },
      select,
    });
  }

  async updateMany(roleUpdateManyArgs: Prisma.RoleUpdateManyArgs) {
    this.logger.info(
      '[Role] Updating multiple roles',
      createSafeLogData({
        operation: 'UPDATE_MANY',
        table: 'role',
        where: roleUpdateManyArgs.where,
        data: roleUpdateManyArgs.data,
      }),
    );
    const result = await this.prisma.role.updateMany(roleUpdateManyArgs);
    this.logger.info(
      '[Role] Multiple roles updated successfully',
      createSafeLogData({
        operation: 'UPDATE_MANY',
        table: 'role',
        count: result.count,
      }),
    );
    return result;
  }

  async updateUnique(id: number, data: Prisma.RoleUpdateManyArgs['data']) {
    const oldData = await this.prisma.role.findUnique({ where: { id } });
    this.logger.info(
      '[Role] Updating role',
      createSafeLogData({
        operation: 'UPDATE',
        table: 'role',
        id: id,
        oldData: oldData,
        newData: data,
      }),
    );
    const result = await this.prisma.role.update({
      where: { id: id },
      data,
    });
    this.logger.info(
      '[Role] Role updated successfully',
      createSafeLogData({
        operation: 'UPDATE',
        table: 'role',
        id: id,
        result: result,
      }),
    );
    return result;
  }

  /**
   * 在事务中更新角色及其页面权限，确保原子性
   * @param id 角色 ID
   * @param roleData 角色更新数据
   * @param pageIds 页面 ID 数组（可选）
   */
  async updateRoleWithPages(
    id: number,
    roleData: Prisma.RoleUpdateManyArgs['data'],
    pageIds?: number[],
  ) {
    // 先准备 roleResources 数据模板
    const roleResourcesTemplate =
      pageIds && pageIds.length > 0
        ? await this.prepareRoleResourcesFromPages(pageIds)
        : [];

    // 构建事务操作数组
    const oldRole = await this.prisma.role.findUnique({ where: { id } });
    this.logger.info(
      '[Role] Updating role with pages in transaction',
      createSafeLogData({
        operation: 'UPDATE_WITH_PAGES',
        table: 'role',
        id: id,
        oldData: oldRole,
        newRoleData: roleData,
        pageIds: pageIds,
        roleResourcesTemplate: roleResourcesTemplate,
      }),
    );
    const operations: any[] = [
      // 1. 更新角色基本信息
      this.prisma.role.update({
        where: { id },
        data: roleData,
      }),
    ];

    // 2. 处理页面权限和资源权限更新
    if (pageIds !== undefined && pageIds !== null) {
      const syncOperations = await this.syncRolePagesAndResources(
        id,
        pageIds,
        roleResourcesTemplate,
      );
      operations.push(...syncOperations);
    }

    // 执行事务，返回第一个操作的结果（更新后的角色）
    const results = await this.prisma.$transaction(operations);
    this.logger.info(
      '[Role] Role with pages updated successfully',
      createSafeLogData({
        operation: 'UPDATE_WITH_PAGES',
        table: 'role',
        id: id,
        result: results[0],
      }),
    );
    return results[0];

    // 暂时注释掉事务执行，仅返回更新后的角色信息
    // console.log('⚠️  数据库事务已被注释，不会实际执行更新操作');
    // return await this.prisma.role.findUnique({
    //   where: { id },
    // });
  }

  async deleteMany(roleDeleteManyArgs: Prisma.RoleDeleteManyArgs) {
    const oldData = await this.prisma.role.findMany({
      where: roleDeleteManyArgs.where,
    });
    this.logger.info(
      '[Role] Deleting multiple roles',
      createSafeLogData({
        operation: 'DELETE_MANY',
        table: 'role',
        where: roleDeleteManyArgs.where,
        oldData: oldData,
      }),
    );
    const result = await this.prisma.role.deleteMany(roleDeleteManyArgs);
    this.logger.info(
      '[Role] Multiple roles deleted successfully',
      createSafeLogData({
        operation: 'DELETE_MANY',
        table: 'role',
        count: result.count,
      }),
    );
    return result;
  }

  async deleteUnique(id: number) {
    const oldData = await this.prisma.role.findUnique({ where: { id } });
    this.logger.info(
      '[Role] Deleting role',
      createSafeLogData({
        operation: 'DELETE',
        table: 'role',
        id: id,
        oldData: oldData,
      }),
    );
    await this.prisma.role.delete({
      where: { id: id },
    });
    this.logger.info(
      '[Role] Role deleted successfully',
      createSafeLogData({
        operation: 'DELETE',
        table: 'role',
        id: id,
      }),
    );
    return { count: 1 };
  }

  async count(roleCountArgs?: Prisma.RoleCountArgs) {
    return await this.prisma.role.count(roleCountArgs);
  }

  async groupBy(roleGroupByArgs: Prisma.RoleGroupByArgs) {
    return await this.prisma.role.groupBy(roleGroupByArgs as any);
  }

  async aggregate(roleAggregateArgs: Prisma.RoleAggregateArgs) {
    return await this.prisma.role.aggregate(roleAggregateArgs);
  }
}
