// guards/base-group.guard.ts
import {
  Injectable,
  NotFoundException,
  ForbiddenException,
} from '@nestjs/common';
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 { Timeline } from '@/entities/timeline.entity';

export enum PermissionLevel {
  MEMBER = 'member',
  ADMIN = 'admin',
  OWNER = 'owner',
}

@Injectable()
export abstract class BaseGroupGuard {
  constructor(
    protected groupMemberRepo: Repository<GroupMember>,
    protected tripRepo: Repository<Trip>,
    protected mapRepo: Repository<Map>,
    protected timelineRepo: Repository<Timeline>,
  ) {}

  protected async getGroupIdFromRequest(req: any): Promise<string | null> {
    const path = req.route?.path || req.url;
    
    // Lấy ID từ các nguồn khác nhau
    const idFromParam = req.params?.id;
    const idFromQuery = req.query?.id || req.query?.tripId || req.query?.mapId || req.query?.groupId;
    const idFromBody = req.body?.id || req.body?.tripId || req.body?.mapId || req.body?.groupId;

    // Xử lý theo route
    if (path.includes('/maps')) {
      return this.getGroupIdFromMapRoute(req, idFromParam, idFromQuery, idFromBody);
    } 
    
    if (path.includes('/trips')) {
      return this.getGroupIdFromTripRoute(req, idFromParam, idFromQuery, idFromBody);
    }

    if (path.includes('/timelines')) {
      return this.getGroupIdFromTimelineRoute(req, idFromParam, idFromQuery, idFromBody);
    }
    
    // Route khác (groups, notifications,...)
    return idFromParam || idFromQuery || idFromBody || null;
  }

  private async getGroupIdFromMapRoute(
    req: any, 
    idFromParam: string, 
    idFromQuery: string, 
    idFromBody: string
  ): Promise<string | null> {
    const tripId = req.query?.tripId || req.body?.tripId || req.params?.tripId;
    const mapId = idFromParam || req.query?.mapId || req.body?.mapId || 
                   (!tripId ? idFromBody : undefined);

    if (tripId) {
      const trip = await this.tripRepo.findOne({
        where: { id: String(tripId) },
        relations: ['group'],
      });
      if (!trip) {
        throw new NotFoundException('Không tìm thấy chuyến đi (Trip not found)');
      }
      return trip.group?.id || null;
    }

    if (mapId) {
      const map = await this.mapRepo.findOne({
        where: { id: String(mapId) },
        relations: ['trip', 'trip.group'],
      });
      if (!map) {
        throw new NotFoundException('Không tìm thấy bản đồ (Map not found)');
      }
      return map.trip?.group?.id || null;
    }

    return null;
  }

  private async getGroupIdFromTimelineRoute(
    req: any, 
    idFromParam: string, 
    idFromQuery: string, 
    idFromBody: string
  ): Promise<string | null> {
    const tripId = req.query?.tripId || req.body?.tripId || req.params?.tripId;
    const timelineId = idFromParam || req.query?.id || req.body?.id || 
                   (!tripId ? idFromBody : undefined);

    if (tripId) {
      const trip = await this.tripRepo.findOne({
        where: { id: String(tripId) },
        relations: ['group'],
      });
      if (!trip) {
        throw new NotFoundException('Không tìm thấy chuyến đi (Trip not found)');
      }
      return trip.group?.id || null;
    }

    if (timelineId) {
      const map = await this.timelineRepo.findOne({
        where: { id: String(timelineId) },
        relations: ['trip', 'trip.group'],
      });
      if (!map) {
        throw new NotFoundException('Không tìm thấy lịch trình');
      }
      return map.trip?.group?.id || null;
    }

    return null;
  }

  private async getGroupIdFromTripRoute(
    req: any,
    idFromParam: string,
    idFromQuery: string,
    idFromBody: string
  ): Promise<string | null> {
    const tripId = idFromParam || idFromQuery || idFromBody;

    if (tripId) {
      const trip = await this.tripRepo.findOne({
        where: { id: String(tripId) },
        relations: ['group'],
      });
      if (!trip) {
        throw new NotFoundException('Không tìm thấy chuyến đi');
      }
      return trip.group?.id || null;
    }

    return null;
  }

  protected async checkMemberPermission(
    req: any, 
    userId: string,
    groupId: string,
    requiredLevel: PermissionLevel
  ): 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 role = member.role;
    const roleLevels = {
      [PermissionLevel.MEMBER]: ['OWNER', 'ADMIN', 'MEMBER', 'VIEWER'],
      [PermissionLevel.ADMIN]: ['OWNER', 'ADMIN'],
      [PermissionLevel.OWNER]: ['OWNER'],
    };

    if (!roleLevels[requiredLevel]?.includes(role)) {
      const errorMessages = {
        [PermissionLevel.MEMBER]: 'Bạn không có quyền truy cập',
        [PermissionLevel.ADMIN]: 'Chỉ owner hoặc admin mới có quyền',
        [PermissionLevel.OWNER]: 'Chỉ owner mới có quyền',
      };
      throw new ForbiddenException(errorMessages[requiredLevel]);
    }

    // Thêm thông tin role vào request để sử dụng sau
    req.userRole = role;
    req.isLeader = role === GroupRole.OWNER || role === GroupRole.ADMIN;

    return true;
  }
}