import { Injectable } from '@nestjs/common';
import { PrismaService } from '../prisma/prisma.service';
import { CreateUserDto } from './dto/create-user.dto';
import { UpdateUserDto } from './dto/update-user.dto';
import * as bcrypt from 'bcrypt';

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

  async create(createUserDto: CreateUserDto) {
    try {
      const saltOrRounds = 10;
      const hash = await bcrypt.hash(createUserDto.password, saltOrRounds);
      return this.prisma.user.create({
        data: {
          phone: createUserDto.phone,
          email: createUserDto.email,
          password: hash,
          status: createUserDto.status,
          role_id: createUserDto.role_id,
          userDetail: {
            create: {
              first_name: createUserDto.first_name,
              last_name: createUserDto.last_name,
              delay_ratio: Number(createUserDto.delay_ratio),
              delay_time: createUserDto.delay_time,
              personal_code: parseInt(createUserDto.personal_code),
              vacation_remained: parseInt(createUserDto.vacation_remained),
            },
          },
        },
        select: {
          id: true,
          phone: true,
          email: true,
          status: true,
          createdAt: true,
          userDetail: {
            select: {
              first_name: true,
              last_name: true,
            },
          },
        },
      });
    } catch (e) {
      return e.errors;
    }
  }

  async findAll(page, url, per_page = 10) {
    try {
      const count = await this.prisma.user.count();
      const howManyPage = Math.ceil(count / per_page);
      const buildPages = () => {
        let pages = [];

        if (page != '1') {
          pages.push({
            text: 'قبلی',
            link: parseInt(page) - 1,
          });
          if (page > 2) {
            pages.push({
              text: '...',
              link: null,
            });
          }
          pages.push({
            text: parseInt(page) - 1,
            link: parseInt(page) - 1,
          });
        }

        pages.push({
          text: page,
          link: page,
        });

        if (page != howManyPage) {
          pages.push({
            text: parseInt(page) + 1,
            link: parseInt(page) + 1,
          });
          // 5 < 4 + 2
          if (howManyPage - 1 > page) {
            pages.push({
              text: '...',
              link: null,
            });
          }
          pages.push({
            text: 'بعدی',
            link: parseInt(page) + 1,
            active: false,
          });
        }
        return pages;
      };

      const _data = await this.prisma.user.findMany({
        orderBy: [{ createdAt: 'desc' }],
        select: {
          id: true,
          phone: true,
          email: true,
          status: true,
          createdAt: true,
          userDetail: {
            select: {
              first_name: true,
              last_name: true,
            },
          },
        },
        take: per_page,
        skip: per_page * (page - 1),
      });

      return {
        data: _data,
        count: count,
        page_count: howManyPage,
        per_page: per_page,
        active_page: parseInt(page),
        last_page: howManyPage,
        pages: buildPages(),
      };
    } catch (e) {
      return e.errors;
    }
  }

  findOne(id: string) {
    return this.prisma.user.findUniqueOrThrow({
      where: { id },
      select: {
        id: true,
        phone: true,
        email: true,
        status: true,
        createdAt: true,
        role_id: true,
        userDetail: {
          select: {
            first_name: true,
            last_name: true,
            delay_time: true,
            delay_ratio: true,
            personal_code: true,
            manager_id: true,
            vacation_remained: true,
          },
        },
      },
    });
  }

  async update(id: string, updateUserDto: UpdateUserDto) {
    if (updateUserDto.password) {
      const saltOrRounds = 10;
      const hash = await bcrypt.hash(updateUserDto.password, saltOrRounds);
      this.prisma.user.update({
        where: { id },
        data: {
          password: hash,
        },
      });
    }
    return this.prisma.user.update({
      where: { id },
      data: {
        phone: updateUserDto.phone,
        email: updateUserDto.email,
        status: updateUserDto.status,
        role_id: updateUserDto.role_id,
        userDetail: {
          update: {
            first_name: updateUserDto.first_name,
            last_name: updateUserDto.last_name,
            delay_ratio: Number(updateUserDto.delay_ratio),
            delay_time: updateUserDto.delay_time,
            vacation_remained: parseInt(updateUserDto.vacation_remained),
            manager_id:
              updateUserDto.manager_id === 'null'
                ? null
                : updateUserDto.manager_id,
          },
        },
      },
      select: {
        id: true,
        phone: true,
        email: true,
        status: true,
        createdAt: true,
        userDetail: {
          select: {
            first_name: true,
            last_name: true,
          },
        },
      },
    });
  }

  remove(id: string) {
    return this.prisma.user.delete({
      where: { id },
      select: {
        id: true,
        phone: true,
        email: true,
        status: true,
        createdAt: true,
        userDetail: {
          select: {
            first_name: true,
            last_name: true,
          },
        },
      },
    });
  }

  async me(id: string) {
    const userDetail = await this.prisma.user.findFirst({
      where: { id },
      select: {
        id: true,
        phone: true,
        email: true,
        status: true,
        createdAt: true,
        userDetail: {
          select: {
            first_name: true,
            last_name: true,
          },
        },
      },
    });
    const Notifications = await this.prisma.notification.findMany({
      where: {
        Notification_Receiver: {
          some: {
            user_id: id,
            isRead: false,
          },
        },
      },
    });
    const Notification_count = Notifications.length;
    return {
      ...userDetail,
      notification_count: Notification_count,
    };
  }

  roles() {
    return this.prisma.role.findMany();
  }

  users() {
    return this.prisma.user.findMany({
      select: {
        id: true,
        userDetail: {
          select: {
            first_name: true,
            last_name: true,
          },
        },
      },
    });
  }
}
