import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
// import { VendorEntity } from "src/entities/vendor.entity";
import { Repository } from 'typeorm';
import { CreateVendorDto } from './dtos/CreateVendorDto.dto';
import { VendorsEntity } from 'src/entities/Vendors.entity';
import {
  getSkipOffset,
  paginate,
} from 'src/config/pagination/pagination.service';
import { Response } from 'src/config/pagination/paginationDto';
import { FileService } from 'src/services/file.service';
import { plainToInstance } from 'class-transformer';
import { RemoveAttachmentDto } from '../visa-commission/dto/remove-attachment.dto';
import { AddAttachmentDto } from '../visa-commission/dto/add-attachment.dto';

@Injectable()
export class VendorsService {
  constructor(
    private fileService: FileService,
    @InjectRepository(VendorsEntity) private repo: Repository<VendorsEntity>,
  ) {}

  async getTotalVendors(): Promise<number> {
    return await this.repo.count();
  }

  create(dto: CreateVendorDto) {
    return this.repo.save(this.repo.create(dto));
  }

  async edit(id: any, updateVendorDto: any): Promise<any> {
    const vendor = await this.findOne(id);
    this.repo.merge(vendor, updateVendorDto);
    return await this.repo.save(vendor);
  }

  async updateStatus(userId: string, updateStatusDto: any) {
    const { ids, action } = updateStatusDto;

    // Execute bulk update query
    return await this.repo
      .createQueryBuilder()
      .update()
      .set({
        status: action === 'activate' ? 'active' : 'inactive', // Status mapping
        // modified_by_user: Number(userId), // Track updater
      })
      .where('id IN (:...ids)', { ids })
      .execute();
  }

  findAlls() {
    return this.repo.find();
  }

  async findAll(searchDto: any): Promise<Response<VendorsEntity>> {
    const query = this.repo
      .createQueryBuilder('vendor')
      .orderBy('vendor.id', 'DESC');

    if (searchDto.search_title) {
      console.log({ searchDto });
      query.andWhere(
        `(vendor.name LIKE :search OR vendor.contact_person LIKE :search OR vendor.email LIKE :search OR vendor.phone LIKE :search OR vendor.notes LIKE :search)`,
        {
          search: `%${searchDto.search_title}%`,
        },
      );
    }

    if (searchDto.status && searchDto.status.length > 0) {
      query.andWhere('vendor.status IN (:...status)', {
        status: searchDto.status,
      });
    }

    if (searchDto.created_by && searchDto.created_by.length > 0) {
      query.andWhere('vendor.created_by IN (:...created_by)', {
        created_by: searchDto.created_by,
      });
    }

    if (searchDto.updated_by && searchDto.updated_by.length > 0) {
      query.andWhere('vendor.modified_by IN (:...updated_by)', {
        updated_by: searchDto.updated_by,
      });
    }

    if (searchDto.contract_start_date) {
      const { from, to } = searchDto.contract_start_date;
      if (from && to) {
        query.andWhere(
          'vendor.contract_start BETWEEN :updatedFrom AND :updatedTo',
          {
            updatedFrom: new Date(from),
            updatedTo: new Date(to),
          },
        );
      } else if (from) {
        query.andWhere('vendor.contract_start >= :updatedFrom', {
          updatedFrom: new Date(from),
        });
      } else if (to) {
        query.andWhere('vendor.contract_start <= :updatedTo', {
          updatedTo: new Date(to),
        });
      }
    }

    if (searchDto.contract_end_date) {
      const { from, to } = searchDto.contract_end_date;

      if (from && to) {
        query.andWhere(
          'vendor.contract_end BETWEEN :updatedFrom AND :updatedTo',
          {
            updatedFrom: new Date(from),
            updatedTo: new Date(to),
          },
        );
      } else if (from) {
        query.andWhere('vendor.contract_end >= :updatedFrom', {
          updatedFrom: new Date(from),
        });
      } else if (to) {
        query.andWhere('vendor.contract_end <= :updatedTo', {
          updatedTo: new Date(to),
        });
      }
    }

    if (searchDto.created_on) {
      const { from, to } = searchDto.created_on;

      if (from && to) {
        query.andWhere(
          'vendor.created_at BETWEEN :createdFrom AND :createdTo',
          {
            createdFrom: from,
            createdTo: to,
          },
        );
      } else if (from) {
        query.andWhere('vendor.created_at >= :createdFrom', {
          createdFrom: from,
        });
      } else if (to) {
        query.andWhere('vendor.created_at <= :createdTo', {
          createdTo: to,
        });
      }
    }

    if (searchDto.updated_on) {
      const { from, to } = searchDto.updated_on;

      if (from && to) {
        query.andWhere(
          'vendor.updated_at BETWEEN :updatedFrom AND :updatedTo',
          {
            updatedFrom: from,
            updatedTo: to,
          },
        );
      } else if (from) {
        query.andWhere('vendor.updated_at >= :updatedFrom', {
          updatedFrom: from,
        });
      } else if (to) {
        query.andWhere('vendor.updated_at <= :updatedTo', {
          updatedTo: to,
        });
      }
    }

    const [skip, limit] = getSkipOffset(searchDto);
    const [data, total] = await query.skip(skip).take(limit).getManyAndCount();

    const pagination = paginate(total, searchDto.per_page, searchDto.page);

    return {
      list: data,
      pagination,
    };
  }

  findOne(id: number) {
    return this.repo.findOne({ where: { id } });
  }

  async update(id: number, dto: CreateVendorDto) {
    await this.repo.update(id, dto);
    return this.findOne(id);
  }

  remove(id: number) {
    return this.repo.delete(id);
  }
  /**
   * addAttachments - Adds new file attachments to an existing bonus receipt
   *
   * @param params - Contains bonus receipt ID and new file attachments
   * @param userData - User data for audit trail
   * @returns Original parameters (for confirmation)
   */
  async getAttachments(id: string): Promise<any> {
    return await this.repo
      .createQueryBuilder('main')
      .select(['main.id', 'main.attachment_file'])
      .where('main.id = :id', { id })
      .orderBy('main.id', 'DESC')
      .getOne();
  }

  async addAttachments(params: AddAttachmentDto, userData: any): Promise<any> {
    let repository;
    repository = this.repo;

    const record = await repository
      .createQueryBuilder()
      .where('id = :id', { id: params.id })
      .getOne();

    const updatedAttachments = record.attachment_file
      ? [...record.attachment_file, ...params.attachment_file]
      : params.attachment_file;

    if (updatedAttachments.length) {
      const entity = plainToInstance(VendorsEntity, {
        attachment_file: updatedAttachments,
        // modified_by_user: userData.id,
      });

      await repository.update({ id: params.id }, entity);
    }

    return params;
  }

  async removeAttachments(
    params: RemoveAttachmentDto,
    userData: any,
  ): Promise<any> {
    let repository;
    repository = this.repo;

    const record = await repository
      .createQueryBuilder()
      // .where('id = :id', { id: params.row_id })
      .where('id = :id', { id: 1 })
      .getOne();

    if (!record?.attachment_file?.length) return params;

    const updatedAttachments = record.attachment_file.filter(
      (file: string) => file !== params.file_name,
    );

    if (updatedAttachments.length !== record.attachment_file.length) {
      const entity = plainToInstance(VendorsEntity, {
        attachment_file: updatedAttachments,
        modified_by_user: userData.id,
      });

      await repository.update({ id: 1 }, entity);
      await this.fileService.removeFile(params.file_name);
    }

    return params;
  }
}
