import { BadRequestException, Injectable } from '@nestjs/common';
import { CreateVacationDto } from './dto/create-vacation.dto';
import { UpdateVacationDto } from './dto/update-vacation.dto';
import { PrismaService } from '../prisma/prisma.service';
import * as MomentJ from 'moment-jalaali';

@Injectable()
export class VacationsService {
  constructor(private prisma: PrismaService) {}

  async create(createVacationDto: CreateVacationDto, user_id) {
    const user = await this.prisma.userDetail.findFirst({
      where: { user_id },
      select: {
        vacation_remained: true,
      },
    });

    const duration = MomentJ.duration(
      MomentJ(createVacationDto.to).diff(createVacationDto.from),
    );
    const minutes_duration =
      createVacationDto.type === 'daily'
        ? Math.floor(duration.asDays()) * 8 * 60
        : Math.floor(duration.asMinutes());

    if (minutes_duration > user.vacation_remained) {
      return false;
    } else {
      const newVac = await this.prisma.vacation.create({
        data: {
          from: createVacationDto.from,
          to: createVacationDto.to,
          status: 'pending',
          type: createVacationDto.type,
          user_id: user_id,
          description: createVacationDto.description,
        },
      });
      // await this.prisma.userDetail.update({
      //   where: { user_id },
      //   data: {
      //     vacation_remained: user.vacation_remained - minutes_duration,
      //   },
      // });
      return true;
    }
  }

  findAll(user_id, year, month) {
    const jalali = MomentJ(`${year}/${month}/1`, 'jYYYY-jM-jD');
    const start = jalali.format('YYYY-MM-DD H:mm:ss');
    jalali.jMonth(parseInt(month) - 1);
    const end = jalali.endOf('jMonth').format('YYYY-MM-DD H:mm:ss');
    return this.prisma.vacation.findMany({
      where: {
        from: {
          gte: new Date(start).toISOString(),
          lte: new Date(end).toISOString(),
        },
        user_id: user_id,
      },
    });
  }

  findOne(id: string) {
    return this.prisma.vacation.findUnique({
      where: { id },
    });
  }

  async update(id: string, updateVacationDto: UpdateVacationDto) {
    if (updateVacationDto.manager === true) {
      const vac = await this.prisma.vacation.findUnique({ where: { id } });
      const user = await this.prisma.userDetail.findFirst({
        where: { user_id: vac.user_id },
        select: {
          vacation_remained: true,
        },
      });
      const duration = MomentJ.duration(MomentJ(vac.to).diff(vac.from));
      const minutes_duration =
        vac.type === 'daily'
          ? Math.floor(duration.asDays()) * 8 * 60
          : Math.floor(duration.asMinutes());

      if (
        (vac.status === 'pending' || vac.status === 'denied') &&
        updateVacationDto.status === 'accepted'
      ) {
        if (minutes_duration > user.vacation_remained) {
          return false;
        } else {
          await this.prisma.userDetail.update({
            where: { user_id: vac.user_id },
            data: {
              vacation_remained: user.vacation_remained - minutes_duration,
            },
          });
          return this.prisma.vacation.update({
            where: { id },
            data: {
              status: updateVacationDto.status,
            },
          });
        }
      } else if (
        vac.status === 'accepted' &&
        (updateVacationDto.status === 'pending' ||
          updateVacationDto.status === 'denied')
      ) {
        if (minutes_duration > user.vacation_remained) {
          return false;
        } else {
          await this.prisma.userDetail.update({
            where: { user_id: vac.user_id },
            data: {
              vacation_remained: user.vacation_remained + minutes_duration,
            },
          });
          return this.prisma.vacation.update({
            where: { id },
            data: {
              status: updateVacationDto.status,
            },
          });
        }
      } else {
        return this.prisma.vacation.update({
          where: { id },
          data: {
            status: updateVacationDto.status,
          },
        });
      }
    } else {
      const vacation = await this.prisma.vacation.findUnique({
        where: { id },
      });
      if (vacation && vacation.status !== 'pending') {
        throw new BadRequestException('You Can not update!');
      }
      return this.prisma.vacation.update({
        where: { id },
        data: {
          from: updateVacationDto.from,
          to: updateVacationDto.to,
          type: updateVacationDto.type,
          description: updateVacationDto.description,
        },
      });
    }
  }

  remove(id: string) {
    return `This action removes a #${id} vacation`;
  }

  async managerFindAll(filter, year, month, user_id) {
    const jalali = MomentJ(`${year}/${month}/1`, 'jYYYY-jM-jD');
    const start = jalali.format('YYYY-MM-DD H:mm:ss');
    jalali.jMonth(parseInt(month) - 1);
    const end = jalali.endOf('jMonth').format('YYYY-MM-DD H:mm:ss');
    const this_user = await this.prisma.user.findUnique({
      where: { id: user_id },
      include: {
        userDetail: true,
      },
    });
    const dataWhere = {
      from: {
        gte: new Date(start).toISOString(),
        lte: new Date(end).toISOString(),
      },
      user: {
        userDetail: this_user.userDetail.manager_id
          ? {
              manager_id: user_id,
            }
          : {},
      },
    };
    const data = this.prisma.vacation.findMany({
      where:
        filter === 'all' ? { ...dataWhere } : { ...dataWhere, status: filter },
      select: {
        id: true,
        from: true,
        to: true,
        description: true,
        status: true,
        type: true,
        user: {
          select: {
            userDetail: {
              select: {
                first_name: true,
                last_name: true,
              },
            },
          },
        },
      },
    });
    return data;
  }
}
