import { ResourcePermission } from '@/entities/resource-permission.entity';
import { Resource } from '@/entities/resource.entity';
import { Role } from '@/entities/role.entity';
import CoreService from '@/system/core/core-service';
import AppResponse from '@/system/response/ktq-response';
import { removeFalsy } from '@/ultils/fn';
import { BadRequestException, Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { paginate, Paginated, PaginateQuery } from 'nestjs-paginate';
import { Not, Repository } from 'typeorm';
import { CreateResourceRoleDto } from './dtos/create-resource-role.dto';
import { SystemLang } from '@/system/lang/system.lang';
import { RolesService } from '../roles/roles.service';

@Injectable()
export class ResourceService extends CoreService<Resource> {
  constructor(
    @InjectRepository(Resource)
    readonly repo: Repository<Resource>,
    @InjectRepository(ResourcePermission)
    readonly resourcePermissionRepo: Repository<ResourcePermission>,
    private readonly roleService: RolesService,
  ) {
    super(
      repo,
      {
        sortableColumns: ['id', 'name', 'created_at'],
        where: { type: 'controller' },
        defaultSortBy: [['id', 'DESC']],
        searchableColumns: ['name', 'description', 'method_name'],
        filterableColumns: {
          name: true,
          created_at: true,
          updated_at: true,
          group_key: true,
        },
        relations: {
          resource_permissions: true,
        },
      },
      Resource,
    );
  }

  protected async beforeIndex(values: Paginated<Resource>) {
    const { data } = values;
    for (let item of data) {
      const children = await this.repo.find({
        where: { type: 'method', group_key: item.group_key },
      });
      item.children = children;
    }
  }

  async resourceByRole(role_id: Role['id'], { ...query }: PaginateQuery) {
    const data = await paginate(query, this.repo, {
      sortableColumns: ['id'],
      searchableColumns: ['id', 'name', 'roles.role_name', 'path', 'group_key'],
      defaultLimit: 10,
      defaultSortBy: [['created_at', 'DESC']],
      maxLimit: 100,
      filterableColumns: {
        'roles.id': true,
      },
      relations: {
        roles: true,
      },
      where: {
        type: 'controller',
      },
    });

    for (let item of data.data) {
      const children = await this.repo.find({
        where: {
          group_key: item.group_key,
          type: 'method',
        },
        relations: { roles: true },
      });

      item.children = children.map((i) => {
        i['checked'] = i.roles.map((i) => i.id).includes(Number(role_id));

        return i;
      });

      item['checked'] = item.roles
        .map((role) => role.id)
        .includes(Number(role_id));
    }

    return AppResponse.toPagination<Resource>(data, true, this.dtoClass);
  }

  async updateResouceRole(
    _: Role['id'],
    { resource_ids, role_id }: CreateResourceRoleDto,
  ) {
    const role = await this.roleService.repo.findOne({
      where: { id: role_id },
    });

    const newResource = resource_ids.map((item) => {
      return this.repo.create({ id: item });
    });

    role.resources = newResource;

    const result = await this.roleService.repo.save(role);

    if (!result)
      throw new BadRequestException(
        AppResponse.toResponse(false, {
          message: SystemLang.getText('messages', 'error'),
        }),
      );

    return AppResponse.toResponse(true);
  }
}
