import { Injectable } from "@nestjs/common"
import { InjectRepository } from "@nestjs/typeorm"
import { Brackets, Repository } from "typeorm"
import { BaseAbstractRepository } from "../../../common/repository/base.repository"
import { TeamMember } from "../entities/team_member.entity"
import { failureResponse } from "src/common/response/response"
import { messageKey } from "src/constants/message-keys"

@Injectable()
export class TeamMemberRepository extends BaseAbstractRepository<TeamMember> {
  constructor(
    @InjectRepository(TeamMember)
    private readonly teamMemberRepository: Repository<TeamMember>,
  ) {
    super(teamMemberRepository)
  }

  async findAllTeamMembersWithFilters({
    search,
    filters,
    take,
    skip,
    sortColumn,
    sortOrder,
  }: {
    search?: string
    filters: {
      departmentIds?: number[]
      roleIds?: number[]
      reportingTo?: number
      status?: string[]
    }
    take: number
    skip: number
    sortColumn: string
    sortOrder: "ASC" | "DESC"
  }): Promise<{ data: any[]; count: number }> {
    // ✅ Proper return type
    try {
      const qb = this.teamMemberRepository
        .createQueryBuilder("teamMember")
        .leftJoinAndSelect("teamMember.role", "role")
        .leftJoinAndSelect("teamMember.languages", "languages")
        .leftJoinAndSelect("teamMember.department", "department")
        .leftJoinAndSelect("teamMember.business_vertical", "business_vertical")
        .leftJoinAndSelect("teamMember.addresses", "addresses")
        .leftJoinAndSelect("addresses.city", "city")
        .leftJoinAndSelect("addresses.state", "state")
        .leftJoinAndSelect("addresses.country", "country")
        .leftJoinAndSelect("teamMember.id_proofs", "id_proofs")
        .leftJoinAndSelect("teamMember.reporting_to", "reporting_to")
        .leftJoinAndSelect("teamMember.vehicles", "vehicles")
        .leftJoinAndSelect(
          "vehicles.vehicle_manufacture",
          "vehicle_manufacture",
        )
        .leftJoinAndSelect("vehicles.vehicleModel", "vehicleModel")
        .where("teamMember.deleted_at IS NULL")
        .select([
          "teamMember.id",
          "teamMember.first_name",
          "teamMember.last_name",
          "teamMember.email",
          "teamMember.phone_number",
          "teamMember.profile_photo",
          "teamMember.status",
          "teamMember.country_code",
          "teamMember.dob",
          "teamMember.gender",
          "teamMember.emergency_contact_name",
          "teamMember.emergency_contact_code",
          "teamMember.emergency_contact_number",
          "teamMember.working_location",
          "teamMember.working_city_location",
          "teamMember.joining_date",
          "teamMember.employment_type",
          "teamMember.current_step",
          "teamMember.form_status",
          "teamMember.duty_status",
          "teamMember.ratings",
          "teamMember.created_at",
          "teamMember.updated_at",
          "role.id",
          "role.name",
          "department.id",
          "department.name",
          "business_vertical.id",
          "business_vertical.name",
          "addresses.id",
          "addresses.address_line_1",
          "addresses.address_line_2",
          "addresses.country",
          "addresses.state",
          "addresses.zipcode",
          "addresses.address_type",
          "addresses.is_emergency_contact",
          "city.id",
          "city.name",
          "state.id",
          "state.name",
          "country.id",
          "country.name",
          "id_proofs.id",
          "id_proofs.document_type",
          "id_proofs.document_number",
          "id_proofs.expiry_date",
          "id_proofs.document_files",
          "id_proofs.created_at",
          "reporting_to.id",
          "reporting_to.first_name",
          "reporting_to.last_name",
          "reporting_to.email",
          "reporting_to.phone_number",
          "vehicles.id",
          "vehicles.registration_number",
          "vehicle_manufacture.id",
          "vehicle_manufacture.name",
          "vehicleModel.id",
          "vehicleModel.name",
          "languages.id",
          "languages.name",
          "languages.code",
        ])

      if (search) {
        qb.andWhere(
          new Brackets((qb) => {
            qb.where("teamMember.first_name ILIKE :search", {
              search: `%${search}%`,
            })
              .orWhere("teamMember.last_name ILIKE :search", {
                search: `%${search}%`,
              })
              .orWhere("teamMember.email ILIKE :search", {
                search: `%${search}%`,
              })
              .orWhere("teamMember.phone_number ILIKE :search", {
                search: `%${search}%`,
              })
          }),
        )
      }

      if (filters.roleIds?.length) {
        qb.andWhere("teamMember.role_id IN (:...roleIds)", {
          roleIds: filters.roleIds,
        })
      }

      if (filters.reportingTo) {
        qb.andWhere("teamMember.reporting_to_id = :reportingTo", {
          reportingTo: filters.reportingTo,
        })
      }

      if (filters.status?.length) {
        qb.andWhere("teamMember.status IN (:...status)", {
          status: filters.status,
        })
      }

      if (filters.departmentIds?.length) {
        qb.innerJoin("teamMember.department", "d").andWhere(
          "d.id IN (:...departmentIds)",
          {
            departmentIds: filters.departmentIds,
          },
        )
      }

      qb.orderBy(`teamMember.${sortColumn}`, sortOrder).skip(skip).take(take)

      const [result, total] = await qb.getManyAndCount()

      const ids = result.map((m) => m.id)
      const avgRows: { teamMemberId: number; averageRating: string }[] =
        await this.teamMemberRepository
          .createQueryBuilder("tm")
          .select("tm.id", "teamMemberId")
          .addSelect("AVG(rr.rating)", "averageRating")
          .leftJoin("tm.receivedRatings", "rr")
          .where("tm.id IN (:...ids)", { ids })
          .groupBy("tm.id")
          .getRawMany()

      const avgMap = new Map(
        avgRows.map((r) => [
          r.teamMemberId,
          Number(r.averageRating).toFixed(1) || 0,
        ]),
      )

      const data = result.map((m) => ({
        ...m,
        ratings: avgMap.get(m.id) ?? 0,
      }))

      return {
        data,
        count: total,
      }
    } catch (error) {
      console.error("Error in findAllTeamMembersWithFilters:", error)
      return {
        data: [],
        count: 0,
      }
    }
  }

  async findOneTeamMember(id: number): Promise<any> {
    try {
      const teamMember = await this.teamMemberRepository
        .createQueryBuilder("teamMember")
        .leftJoinAndSelect("teamMember.role", "role")
        .leftJoinAndSelect("teamMember.department", "department")
        .leftJoinAndSelect("teamMember.languages", "languages")
        .leftJoinAndSelect("teamMember.business_vertical", "business_vertical")
        .leftJoinAndSelect("teamMember.addresses", "addresses")
        .leftJoinAndSelect("addresses.city", "city")
        .leftJoinAndSelect("addresses.state", "state")
        .leftJoinAndSelect("addresses.country", "country")
        .leftJoinAndSelect("teamMember.id_proofs", "id_proofs")
        .leftJoinAndSelect("teamMember.reporting_to", "reporting_to")
        .leftJoinAndSelect("teamMember.state", "working_location")
        .leftJoinAndSelect("teamMember.city", "working_city_location")
        .where("teamMember.id = :id", { id })
        .andWhere("teamMember.deleted_at IS NULL")
        .getOne()

      if (teamMember?.id_proofs && teamMember.id_proofs.length > 0) {
        teamMember.id_proofs = teamMember.id_proofs.map((proof: any) => {
          if (proof.document_files) {
            proof.document_files = proof.document_files
          }
          return proof
        })
      }

      return teamMember
    } catch (error) {
      return failureResponse(500, messageKey.something_went_wrong)
    }
  }
}
