import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { BaseTenantRepository, TenantContextService } from '@iconsulting/shared';
import { IUserProfileRepository } from '../../../domain/repositories/user-profile.repository.interface';
import {
  UserProfileEntity,
  EducationRecord,
  WorkRecord,
  LanguageScore,
  FamilyMember,
  MaritalStatus,
  ImmigrationType,
  PlannedTimeline,
  EducationLevel,
  NetWorthRange,
} from '../../../domain/entities/user-profile.entity';
import { UserProfileORM } from '../../../infrastructure/database/postgres/entities/user-profile.orm';

@Injectable()
export class UserProfilePostgresRepository
  extends BaseTenantRepository<UserProfileEntity, UserProfileORM>
  implements IUserProfileRepository
{
  constructor(
    @InjectRepository(UserProfileORM) repo: Repository<UserProfileORM>,
    tenantContext: TenantContextService,
  ) {
    super(repo, tenantContext);
  }

  async save(profile: UserProfileEntity): Promise<void> {
    const orm = this.toORM(profile);
    orm.tenantId = this.getTenantId();
    await this.repo.save(orm);
  }

  async findById(id: string): Promise<UserProfileEntity | null> {
    const orm = await this.findOneWithTenant({ id } as any);
    return orm ? this.toEntity(orm) : null;
  }

  async findByUserId(userId: string): Promise<UserProfileEntity | null> {
    const orm = await this.findOneWithTenant({ userId } as any);
    return orm ? this.toEntity(orm) : null;
  }

  async update(profile: UserProfileEntity): Promise<void> {
    const orm = this.toORM(profile);
    orm.tenantId = this.getTenantId();
    await this.repo.save(orm);
  }

  async delete(id: string): Promise<void> {
    await this.repo.delete({ id, tenantId: this.getTenantId() } as any);
  }

  async findByTargetCountry(
    countryCode: string,
    options?: { limit?: number; offset?: number },
  ): Promise<UserProfileEntity[]> {
    const query = this.createTenantQueryBuilder('profile')
      .andWhere(':country = ANY(profile.target_countries)', { country: countryCode })
      .orderBy('profile.completion_percentage', 'DESC');

    if (options?.limit) {
      query.take(options.limit);
    }
    if (options?.offset) {
      query.skip(options.offset);
    }

    const orms = await query.getMany();
    return orms.map(orm => this.toEntity(orm));
  }

  async countByCompletionRange(): Promise<{
    low: number;
    medium: number;
    high: number;
  }> {
    const tenantId = this.getTenantId();

    const result = await this.repo.query(
      `
      SELECT
        COUNT(CASE WHEN completion_percentage < 30 THEN 1 END) as low,
        COUNT(CASE WHEN completion_percentage >= 30 AND completion_percentage < 70 THEN 1 END) as medium,
        COUNT(CASE WHEN completion_percentage >= 70 THEN 1 END) as high
      FROM user_profiles
      WHERE tenant_id = $1
      `,
      [tenantId],
    );

    return {
      low: parseInt(result[0]?.low || '0', 10),
      medium: parseInt(result[0]?.medium || '0', 10),
      high: parseInt(result[0]?.high || '0', 10),
    };
  }

  private toORM(entity: UserProfileEntity): UserProfileORM {
    const orm = new UserProfileORM();
    orm.id = entity.id;
    orm.tenantId = this.getTenantId();
    orm.userId = entity.userId;
    orm.fullName = entity.fullName;
    orm.birthDate = entity.birthDate;
    orm.nationality = entity.nationality;
    orm.currentCountry = entity.currentCountry;
    orm.currentCity = entity.currentCity;
    orm.maritalStatus = entity.maritalStatus;
    orm.targetCountries = entity.targetCountries;
    orm.immigrationTypes = entity.immigrationTypes;
    orm.plannedTimeline = entity.plannedTimeline;
    orm.primaryPurpose = entity.primaryPurpose;
    orm.highestEducation = entity.highestEducation;
    orm.educationRecords = entity.educationRecords as unknown as Record<string, unknown>[];
    orm.currentOccupation = entity.currentOccupation;
    orm.totalWorkYears = entity.totalWorkYears;
    orm.workRecords = entity.workRecords as unknown as Record<string, unknown>[];
    orm.languageScores = entity.languageScores as unknown as Record<string, unknown>[];
    orm.familyMembers = entity.familyMembers as unknown as Record<string, unknown>[];
    orm.netWorthRange = entity.netWorthRange;
    orm.hasBusinessExperience = entity.hasBusinessExperience;
    orm.businessYears = entity.businessYears;
    orm.hasOverseasExperience = entity.hasOverseasExperience;
    orm.hasCriminalRecord = entity.hasCriminalRecord;
    orm.hasHealthIssues = entity.hasHealthIssues;
    orm.additionalNotes = entity.additionalNotes;
    orm.completionPercentage = entity.completionPercentage;
    orm.createdAt = entity.createdAt;
    orm.updatedAt = entity.updatedAt;
    return orm;
  }

  private toEntity(orm: UserProfileORM): UserProfileEntity {
    return UserProfileEntity.fromPersistence({
      id: orm.id,
      userId: orm.userId,
      fullName: orm.fullName,
      birthDate: orm.birthDate,
      nationality: orm.nationality,
      currentCountry: orm.currentCountry,
      currentCity: orm.currentCity,
      maritalStatus: orm.maritalStatus,
      targetCountries: orm.targetCountries,
      immigrationTypes: orm.immigrationTypes,
      plannedTimeline: orm.plannedTimeline,
      primaryPurpose: orm.primaryPurpose,
      highestEducation: orm.highestEducation,
      educationRecords: orm.educationRecords as unknown as EducationRecord[],
      currentOccupation: orm.currentOccupation,
      totalWorkYears: orm.totalWorkYears,
      workRecords: orm.workRecords as unknown as WorkRecord[],
      languageScores: orm.languageScores as unknown as LanguageScore[],
      familyMembers: orm.familyMembers as unknown as FamilyMember[],
      netWorthRange: orm.netWorthRange,
      hasBusinessExperience: orm.hasBusinessExperience,
      businessYears: orm.businessYears,
      hasOverseasExperience: orm.hasOverseasExperience,
      hasCriminalRecord: orm.hasCriminalRecord,
      hasHealthIssues: orm.hasHealthIssues,
      additionalNotes: orm.additionalNotes,
      completionPercentage: orm.completionPercentage,
      createdAt: orm.createdAt,
      updatedAt: orm.updatedAt,
    });
  }
}
