import {
  BadRequestException,
  Injectable,
  NotFoundException,
} from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { DataSource, Repository } from 'typeorm';

import { Map } from '@/entities/map.entity';
import { Trip } from '@/entities/trip.entity';

import { CreateMapDto } from './dto/create-map.dto';

@Injectable()
export class MapService {
  constructor(
    @InjectRepository(Map)
    private readonly mapRepo: Repository<Map>,

    @InjectRepository(Trip)
    private readonly tripRepo: Repository<Trip>,

    private dataSource: DataSource,
  ) {}

  // =============================
  // CREATE
  // =============================
  async create(dto: CreateMapDto, file: Express.Multer.File) {
    if (!file) {
      throw new BadRequestException('Không tồn tại file');
    }

    const trip = await this.tripRepo.findOne({
      where: { id: dto.tripId },
    });

    if (!trip) {
      throw new NotFoundException('Trip not found');
    }

    const existingActiveMap = await this.mapRepo.findOne({
      where: { 
        trip: { id: dto.tripId }, 
        active: true 
      },
    });

    const isActive = !existingActiveMap;

    const map = this.mapRepo.create({
      name: dto.name,
      routerFileName: file.path,
      trip,
      active: isActive,
    });

    return this.mapRepo.save(map);
  }

  // =============================
  // FIND ALL BY TRIP
  // =============================
  async findByTrip(tripId: string, isLeader: boolean) {
    if (!isLeader) {
      const data = await this.mapRepo.findOne({
        where: {
          trip: {
            id: tripId,
          },
          active: true,
        },
        select: {
          id: true,
          name: true,
          routerFileName: true,
          active: true,
        },
      });

      const response = {
        isLeader: isLeader,
        data: data ? [data] : [],
      };

      return response;
    }
    const data = await this.mapRepo.find({
      where: {
        trip: {
          id: tripId,
        },
      },
      select: {
        id: true,
        name: true,
        routerFileName: true,
        active: true,
      },
      order: {
        createdAt: 'DESC',
      },
    });

    return {
      isLeader: isLeader,
      data: data,
    };
  }

  // =============================
  // FIND ONE
  // =============================
  async findOne(id: string) {
    const map = await this.mapRepo.findOne({
      where: { id, active: true },
      relations: ['trip'],
    });

    if (!map) {
      throw new NotFoundException('Map not found');
    }
    return {
      id: map.id,
      name: map.name,
      routerFileName: map.routerFileName,
      active: map.active,
      tripId: map.trip.id,
    };
  }

  // =============================
  // DELETE
  // =============================
  async delete(id: string) {
    const map = await this.mapRepo.findOne({
      where: { id },
      relations: ['trip'],
    });
    if (!map) {
      throw new NotFoundException('Map not found');
    }

    await this.dataSource.transaction(async (manager) => {
      await manager.delete(Map, map.id);

      if (map.active) {
        const replacement = await manager.findOne(Map, {
          where: { trip: { id: map.trip.id } },
          order: { createdAt: 'DESC' },
        });
        if (replacement) {
          await manager.update(Map, replacement.id, { active: true });
        }
      }
    });

    return {
      message: 'Deleted successfully',
    };
  }

  // =====================================
  // CHANGE ACTIVE MAP
  // =====================================
  async changeActiveMap(tripId: string, mapId: string) {
    const targetMap = await this.mapRepo.findOne({
      where: { id: mapId, trip: { id: tripId } },
      select: { id: true },
    });
    if (!targetMap) {
      throw new NotFoundException('Map not found in this trip');
    }

    await this.dataSource.transaction(async (transactionalEntityManager) => {
      await transactionalEntityManager
        .createQueryBuilder()
        .update(Map)
        .set({ active: false })
        .where('tripId = :tripId', { tripId })
        .execute();

      // 2. Kích hoạt active cho map được chọn
      await transactionalEntityManager
        .createQueryBuilder()
        .update(Map)
        .set({ active: true })
        .where('id = :mapId', { mapId })
        .execute();
    });

    return {
      message: 'Chọn bản đồ thành công',
    };
  }
}
