// guards/permission.guard.ts
import {
  Injectable,
  CanActivate,
  ExecutionContext,
  ForbiddenException,
} from '@nestjs/common';
import { Reflector } from '@nestjs/core';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { GroupMember, GroupRole } from '@/entities/group-member.entity';
import { Trip } from '@/entities/trip.entity';
import { Map } from '@/entities/map.entity';
import { 
  PermissionLevel, 
  PERMISSION_LEVELS, 
  PERMISSION_ERROR_MESSAGES,
  METADATA_KEYS 
} from '@/constants/permission.constant';
import { BaseGroupGuard } from './base-group.guard';
import { Timeline } from '@/entities/timeline.entity';

@Injectable()
export class PermissionGuard extends BaseGroupGuard implements CanActivate {
  constructor(
    @InjectRepository(GroupMember)
    protected groupMemberRepo: Repository<GroupMember>,
    @InjectRepository(Trip)
    protected tripRepo: Repository<Trip>,
    @InjectRepository(Map)
    protected mapRepo: Repository<Map>,
    @InjectRepository(Timeline)
    protected timelineRepo: Repository<Timeline>,
    private reflector: Reflector,
  ) {
    super(groupMemberRepo, tripRepo, mapRepo, timelineRepo);
  }

  async canActivate(context: ExecutionContext): Promise<boolean> {
    const req = context.switchToHttp().getRequest();
    const user = req.user;

    // Kiểm tra public routes
    const isPublic = this.reflector.get<boolean>(
      'isPublic',
      context.getHandler(),
    );
    
    if (isPublic) return true;

    // Kiểm tra skip permission
    const skipPermission = this.reflector.get<boolean>(
      'skipPermission',
      context.getHandler(),
    );
    
    if (skipPermission) return true;

    if (!user) return false;

    // Lấy yêu cầu permission từ metadata
    const requiredPermission = this.reflector.get<PermissionLevel>(
      METADATA_KEYS.PERMISSION,
      context.getHandler(),
    );

    const optionalPermissions = this.reflector.get<PermissionLevel[]>(
      METADATA_KEYS.PERMISSION_OPTIONAL,
      context.getHandler(),
    );

    // Lấy resource info từ metadata
    const resourceInfo = this.reflector.get<{ resourceType: string; idSource?: string }>(
      METADATA_KEYS.PERMISSION_RESOURCE,
      context.getHandler(),
    );

    // Lấy groupId
    let groupId: string | null = null;
    
    if (resourceInfo) {
      // Sử dụng resource info từ decorator
      groupId = await this.getGroupIdFromResource(req, resourceInfo);
    } else {
      // Tự động detect từ request
      groupId = await this.getGroupIdFromRequest(req);
    }

    if (!groupId) {
      throw new ForbiddenException('Không xác định được thông tin nhóm');
    }

    // Nếu có yêu cầu permission cụ thể
    if (requiredPermission) {
      return this.checkPermission(user.id, groupId, requiredPermission, req);
    }

    // Nếu có danh sách permissions cho phép
    if (optionalPermissions && optionalPermissions.length > 0) {
      return this.checkAnyPermission(user.id, groupId, optionalPermissions, req);
    }

    // Default: chỉ cần là member
    return this.checkPermission(user.id, groupId, PermissionLevel.MEMBER, req);
  }

  /**
   * Lấy groupId từ resource được chỉ định trong decorator
   */
  private async getGroupIdFromResource(
    req: any,
    resourceInfo: { resourceType: string; idSource?: string },
  ): Promise<string | null> {
    const { resourceType, idSource } = resourceInfo;

    let id: string | null = null;

    // Lấy ID từ nguồn được chỉ định
    if (idSource === 'param') {
      id = req.params?.[resourceType + 'Id'] || req.params?.id || null;
    } else if (idSource === 'query') {
      id = req.query?.id || req.query?.[resourceType + 'Id'] || null;
    } else if (idSource === 'body') {
      id = req.body?.id || req.body?.[resourceType + 'Id'] || null;
    } else {
      // Tự động detect
      id = req.params?.id || req.query?.id || req.body?.id || null;
    }
    
    if (!id) {
      // Thử lấy từ query/body với tên cụ thể
      id = req.query?.[`${resourceType}Id`] || 
           req.body?.[`${resourceType}Id`] || 
           req.params?.[`${resourceType}Id`] || null;
    }

    if (!id) return null;

    // Lấy groupId dựa trên loại resource
    if (resourceType === 'map') {
      const map = await this.mapRepo.findOne({
        where: { id: String(id) },
        relations: ['trip', 'trip.group'],
      });
      req.trip = map?.trip;
      return map?.trip?.group?.id || null;
    }

    if (resourceType === 'timeline') {
      const map = await this.timelineRepo.findOne({
        where: { id: String(id) },
        relations: ['trip', 'trip.group'],
      });
      req.trip = map?.trip;
      return map?.trip?.group?.id || null;
    }

    if (resourceType === 'trip') {
       const trip = await this.tripRepo
        .createQueryBuilder('trip')
        .leftJoinAndSelect('trip.group', 'group')
        .leftJoinAndSelect('group.members', 'member')
        .leftJoinAndSelect('member.user', 'user')
        .where('trip.id = :tripId', { tripId: String(id) })
        .getOne();
      req.trip = trip;
      
      return trip?.group?.id || null;
    }

    if (resourceType === 'group') {
      return String(id);
    }

    return null;
  }

  /**
   * Kiểm tra một permission cụ thể
   */
  private async checkPermission(
    userId: string,
    groupId: string,
    level: PermissionLevel,
    req: any,
  ): Promise<boolean> {
    const member = await this.groupMemberRepo.findOne({
      where: {
        group: { id: groupId },
        user: { id: userId },
      },
    });

    if (!member) {
      throw new ForbiddenException('Bạn không phải là thành viên của nhóm này');
    }

    const allowedRoles = PERMISSION_LEVELS[level];
    if (!allowedRoles.includes(member.role)) {
      throw new ForbiddenException(PERMISSION_ERROR_MESSAGES[level]);
    }

    // Set thông tin vào request
    req.userRole = member.role;
    req.isLeader = member.role === GroupRole.OWNER || member.role === GroupRole.ADMIN;
    req.groupId = groupId;

    return true;
  }

  /**
   * Kiểm tra bất kỳ permission nào trong danh sách được chấp nhận
   */
  private async checkAnyPermission(
    userId: string,
    groupId: string,
    levels: PermissionLevel[],
    req: any,
  ): Promise<boolean> {
    try {
      // Thử kiểm tra từng level
      for (const level of levels) {
        try {
          await this.checkPermission(userId, groupId, level, req);
          return true;
        } catch (error) {
          // Continue to next level
          continue;
        }
      }
      
      throw new ForbiddenException('Bạn không có quyền truy cập');
    } catch (error) {
      throw new ForbiddenException('Bạn không có quyền truy cập');
    }
  }
}