import { Injectable } from '@nestjs/common';
import { PrismaService } from '@core/database/prisma/prisma.service';
import {
  normalizeMeetingRole,
  isMeetingAdminRole,
  MeetingAttendanceRoleCode,
} from '../utils/meeting-roles';

interface ActorLike {
  userId: string;
  email?: string;
  roles?: Array<{ role?: { code?: string } } | string>;
  organizationRoles?: Record<string, string[]>;
  role?: string;
}

/**
 * 议程能力鉴权 helper：
 *
 * - `isManagerOrCreator(meetingId, actor)`：当前用户是 Administrator / MeetingManager / 该会议的 creator
 * - `isAttendee(meetingId, actor)`：当前用户是该会议的 required attendee 或会议 creator 或 manager
 *
 * 用于 controller 层细粒度判定，跟全局 PermissionsGuard 的"全局权限点"互补：
 *   PermissionsGuard 判 `meeting:agenda:update`（全局开关）
 *   这里判"会议级派生身份"（creator / required attendee）
 */
@Injectable()
export class MeetingAccessService {
  constructor(private readonly prisma: PrismaService) {}

  /** 判定当前 actor 是 Administrator / MeetingManager / 会议 creator。 */
  async isManagerOrCreator(meetingId: string, actor: ActorLike): Promise<boolean> {
    if (this.isAdminOrManager(actor)) return true;

    const meeting = await this.prisma.meeting.findUnique({
      where: { id: meetingId },
      select: { creatorId: true },
    });
    if (!meeting) return false;
    return meeting.creatorId === actor.userId;
  }

  /** 判定当前 actor 是参会人（含 manager / creator 自动通过）。 */
  async isAttendee(meetingId: string, actor: ActorLike): Promise<boolean> {
    if (await this.isManagerOrCreator(meetingId, actor)) return true;

    const exists = await this.prisma.meetingRequiredAttendee.findFirst({
      where: { meetingId, userId: actor.userId },
      select: { id: true },
    });
    return Boolean(exists);
  }

  /** 简单角色判定。 */
  isAdminOrManager(actor: ActorLike): boolean {
    const fromRoles = this.findRole(actor);
    if (fromRoles && isMeetingAdminRole(fromRoles)) return true;
    const fromField = normalizeMeetingRole(actor.role);
    return Boolean(fromField && isMeetingAdminRole(fromField));
  }

  private findRole(actor: ActorLike): MeetingAttendanceRoleCode | null {
    const codes: string[] = [];
    if (actor.roles?.length) {
      for (const item of actor.roles) {
        codes.push(typeof item === 'string' ? item : item?.role?.code ?? '');
      }
    }
    if (actor.organizationRoles) {
      for (const orgRoles of Object.values(actor.organizationRoles)) {
        for (const code of orgRoles) codes.push(code);
      }
    }
    for (const code of codes) {
      const n = normalizeMeetingRole(code);
      if (n && isMeetingAdminRole(n)) return n;
    }
    return null;
  }
}
