import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { LeaveRequest, LeaveStatus } from '../leaves/entities/leave-request.entity';
import { LeaveBalance } from '../leaves/entities/leave-balance.entity';
import { User, Role } from '../users/entities/user.entity';
import dayjs from 'dayjs';
import relativeTime from 'dayjs/plugin/relativeTime';

dayjs.extend(relativeTime);

@Injectable()
export class ReportsDashboardService {
  constructor(
    @InjectRepository(LeaveRequest)
    private readonly leaveRequestRepo: Repository<LeaveRequest>,

    @InjectRepository(LeaveBalance)
    private readonly leaveBalanceRepo: Repository<LeaveBalance>,

    @InjectRepository(User)
    private readonly userRepo: Repository<User>,
  ) {}

  async getDashboardKPIs(currentUser: User) {
    const today      = dayjs().format('YYYY-MM-DD');
    const year       = dayjs().year();
    const monthStart = dayjs().startOf('month').format('YYYY-MM-DD');
    const monthEnd   = dayjs().endOf('month').format('YYYY-MM-DD');

    const userTeamId   = currentUser.team?.id   ?? null;
    const userAgencyId = currentUser.agency?.id ?? null;

    const isManager = [
      Role.AGENCY_MANAGER,
      Role.DIRECTOR,
      Role.TEAM_LEAD,
    ].includes(currentUser.role);

    // ── Absents aujourd'hui ────────────────────────────────────────────────────
    const absentQuery = this.leaveRequestRepo
      .createQueryBuilder('lr')
      .leftJoinAndSelect('lr.user', 'user')
      .leftJoinAndSelect('user.team', 'team')
      .leftJoinAndSelect('lr.leave_type', 'leave_type')
      .where('lr.status = :status', { status: LeaveStatus.APPROVED })
      .andWhere('lr.start_date <= :today', { today })
      .andWhere('lr.end_date >= :today',   { today });

    // Employé → voir uniquement son équipe
    if (currentUser.role === Role.EMPLOYEE && userTeamId) {
      absentQuery.andWhere('user.team_id = :teamId', { teamId: userTeamId });
    } else if (currentUser.role === Role.EMPLOYEE && !userTeamId) {
      absentQuery.andWhere('user.id = :userId', { userId: currentUser.id });
    }

    // Chef d'équipe → voir uniquement son équipe
    if (currentUser.role === Role.TEAM_LEAD && userTeamId) {
      absentQuery.andWhere('user.team_id = :teamId', { teamId: userTeamId });
    }

    const absentToday = await absentQuery.getMany();

    // ── Demandes en attente ────────────────────────────────────────────────────
    const pendingQuery = this.leaveRequestRepo
      .createQueryBuilder('lr')
      .leftJoinAndSelect('lr.user', 'user')
      .leftJoinAndSelect('user.team', 'team')
      .leftJoinAndSelect('lr.leave_type', 'leave_type')
      .where('lr.status IN (:...statuses)', {
        statuses: [
          LeaveStatus.PENDING_N1,
          LeaveStatus.PENDING_N2,
          LeaveStatus.PENDING_N3,
        ],
      })
      .orderBy('lr.created_at', 'ASC');

    if (currentUser.role === Role.EMPLOYEE) {
      pendingQuery.andWhere('lr.user_id = :userId', { userId: currentUser.id });
    } else if (currentUser.role === Role.TEAM_LEAD && userTeamId) {
      pendingQuery.andWhere('user.team_id = :teamId', { teamId: userTeamId });
    }

    const pendingRequests = await pendingQuery.getMany();

    // ── Soldes critiques ───────────────────────────────────────────────────────
    const balanceQuery = this.leaveBalanceRepo
      .createQueryBuilder('b')
      .leftJoinAndSelect('b.user', 'user')
      .leftJoinAndSelect('user.team', 'team')
      .leftJoinAndSelect('b.leave_type', 'leave_type')
      .where('b.year = :year', { year })
      .andWhere('user.is_active = true')
      .andWhere('leave_type.deducts_balance = true')
      .andWhere('(b.acquired - b.taken + b.adjusted) <= 2')
      .andWhere('(b.acquired - b.taken + b.adjusted) >= 0');

    if (currentUser.role === Role.EMPLOYEE) {
      balanceQuery.andWhere('user.id = :userId', { userId: currentUser.id });
    } else if (currentUser.role === Role.TEAM_LEAD && userTeamId) {
      balanceQuery.andWhere('user.team_id = :teamId', { teamId: userTeamId });
    }

    const criticalBalances = await balanceQuery
      .orderBy('(b.acquired - b.taken + b.adjusted)', 'ASC')
      .getMany();

    // ── Congés du mois ─────────────────────────────────────────────────────────
    const monthLeavesQuery = this.leaveRequestRepo
      .createQueryBuilder('lr')
      .leftJoinAndSelect('lr.user', 'user')
      .where('lr.status = :status', { status: LeaveStatus.APPROVED })
      .andWhere('lr.start_date <= :end',   { end:   monthEnd   })
      .andWhere('lr.end_date   >= :start', { start: monthStart });

    if (currentUser.role === Role.EMPLOYEE) {
      monthLeavesQuery.andWhere('lr.user_id = :userId', { userId: currentUser.id });
    }

    const monthLeaves = await monthLeavesQuery.getMany();

    // ── Total utilisateurs ─────────────────────────────────────────────────────
    const totalUsersQuery = this.userRepo
      .createQueryBuilder('user')
      .where('user.is_active = true');

    if (currentUser.role === Role.TEAM_LEAD && userTeamId) {
      totalUsersQuery.andWhere('user.team_id = :teamId', { teamId: userTeamId });
    } else if (currentUser.role === Role.EMPLOYEE) {
      // Un employé voit uniquement lui-même
      totalUsersQuery.andWhere('user.id = :userId', { userId: currentUser.id });
    }

    const totalUsers = await totalUsersQuery.getCount();

    // ── Demandes ce mois ───────────────────────────────────────────────────────
    const monthRequestsQuery = this.leaveRequestRepo
      .createQueryBuilder('lr')
      .leftJoinAndSelect('lr.user', 'user')
      .where('lr.created_at >= :start', { start: monthStart })
      .andWhere('lr.created_at <= :end', { end: monthEnd + 'T23:59:59' });

    if (currentUser.role === Role.EMPLOYEE) {
      monthRequestsQuery.andWhere('lr.user_id = :userId', {
        userId: currentUser.id,
      });
    }

    const monthRequests      = await monthRequestsQuery.getMany();
    const approvedThisMonth  = monthRequests.filter(r => r.status === LeaveStatus.APPROVED).length;
    const rejectedThisMonth  = monthRequests.filter(r => r.status === LeaveStatus.REJECTED).length;

    // ── Mon solde (pour les employés) ──────────────────────────────────────────
    let myBalances: LeaveBalance[] | null = null;
    if (currentUser.role === Role.EMPLOYEE) {
      myBalances = await this.leaveBalanceRepo
        .createQueryBuilder('b')
        .leftJoinAndSelect('b.leave_type', 'leave_type')
        .where('b.user_id = :userId', { userId: currentUser.id })
        .andWhere('b.year = :year', { year })
        .andWhere('leave_type.deducts_balance = true')
        .getMany();
    }

    return {
      role: currentUser.role,

      kpis: {
        total_users:         totalUsers,
        absent_today:        absentToday.length,
        absent_rate_today:   totalUsers > 0
          ? Math.round((absentToday.length / totalUsers) * 100)
          : 0,
        pending_requests:    pendingRequests.length,
        critical_balances:   criticalBalances.length,
        month_leaves:        monthLeaves.length,
        approved_this_month: approvedThisMonth,
        rejected_this_month: rejectedThisMonth,
      },

      absent_today: absentToday.map(lr => ({
        user_id:    lr.user.id,
        user_name:  `${lr.user.first_name} ${lr.user.last_name}`,
        team:       lr.user.team?.name ?? '—',
        leave_type: lr.leave_type.label,
        end_date:   dayjs(lr.end_date).format('DD/MM/YYYY'),
        days_left:  dayjs(lr.end_date).diff(dayjs(), 'day') + 1,
      })),

      pending_requests: pendingRequests.map(lr => ({
        id:            lr.id,
        user_name:     `${lr.user.first_name} ${lr.user.last_name}`,
        team:          lr.user.team?.name ?? '—',
        leave_type:    lr.leave_type.label,
        start_date:    dayjs(lr.start_date).format('DD/MM/YYYY'),
        end_date:      dayjs(lr.end_date).format('DD/MM/YYYY'),
        days_count:    lr.days_count,
        status:        lr.status,
        waiting_since: dayjs(lr.created_at).fromNow(),
      })),

      critical_balances: criticalBalances.map(b => ({
        user_id:    b.user.id,
        user_name:  `${b.user.first_name} ${b.user.last_name}`,
        team:       b.user.team?.name ?? '—',
        leave_type: b.leave_type.label,
        remaining:  +b.acquired - +b.taken + +b.adjusted,
      })),

      // Soldes personnels pour les employés
      my_balances: myBalances?.map(b => ({
        leave_type: b.leave_type.label,
        acquired:   +b.acquired,
        taken:      +b.taken,
        adjusted:   +b.adjusted,
        remaining:  +b.acquired - +b.taken + +b.adjusted,
      })) ?? null,

      period: {
        today,
        month_start: monthStart,
        month_end:   monthEnd,
        year,
      },
    };
  }
}