import { Injectable } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { InjectDataSource, InjectRepository } from '@nestjs/typeorm';
import { DataSource, IsNull, Repository } from 'typeorm';
import { SystemHealthResponse } from './dto/system-health.dto';
import { TestSummaryDto, FarmTestSummaryDto, CowTestDetailDto } from './dto/test-summary.dto';
import { CowModel } from '../cow/entities/cow.entity';
import { FarmModel } from '../farm/entities/farm.entity';
import { GenomeTraitDetailModel } from '../genome/entities/genome-trait-detail.entity';
import { GeneDetailModel } from '../gene/entities/gene-detail.entity';
import { MptModel } from '../mpt/entities/mpt.entity';

@Injectable()
export class SystemService {
  constructor(
    private configService: ConfigService,
    @InjectDataSource() private dataSource: DataSource,
    @InjectRepository(CowModel)
    private readonly cowRepository: Repository<CowModel>,
    @InjectRepository(FarmModel)
    private readonly farmRepository: Repository<FarmModel>,
    @InjectRepository(GenomeTraitDetailModel)
    private readonly genomeTraitDetailRepository: Repository<GenomeTraitDetailModel>,
    @InjectRepository(GeneDetailModel)
    private readonly geneDetailRepository: Repository<GeneDetailModel>,
    @InjectRepository(MptModel)
    private readonly mptRepository: Repository<MptModel>,
  ) {}

  async getHealth(): Promise<SystemHealthResponse> {
    const dbHealth = await this.checkDatabase();

    return {
      status: dbHealth.status === 'connected' ? 'ok' : 'error',
      timestamp: new Date().toISOString(),
      environment: this.configService.get('NODE_ENV') || 'development',
      database: dbHealth,
    };
  }

  private async checkDatabase() {
    const config = {
      host: this.configService.get('POSTGRES_HOST') || 'unknown',
      port: parseInt(this.configService.get('POSTGRES_PORT')) || 5432,
      database: this.configService.get('POSTGRES_DB') || 'unknown',
      user: this.configService.get('POSTGRES_USER') || 'unknown',
    };

    try {
      await this.dataSource.query('SELECT 1');
      return { ...config, status: 'connected' as const };
    } catch (error) {
      return { ...config, status: 'disconnected' as const, error: error.message };
    }
  }

  /**
   * 전체 검사 집계 조회
   * 농가별/개체별 유전체, 유전자, 번식능력 검사 현황
   */
  async getTestSummary(): Promise<TestSummaryDto> {
    // 1. 모든 농가 조회
    const farms = await this.farmRepository.find({
      where: { delDt: IsNull() },
      order: { farmerName: 'ASC' },
    });

    // 2. 각 검사별 cowId 조회 (전체)
    const [genomeCowIds, geneCowIds, mptCowIds] = await Promise.all([
      // 유전체 검사 개체 (형질 데이터 보유)
      this.genomeTraitDetailRepository
        .createQueryBuilder('trait')
        .select('DISTINCT trait.cowId', 'cowId')
        .where('trait.delDt IS NULL')
        .getRawMany()
        .then(rows => rows.map((r: { cowId: string }) => r.cowId).filter(Boolean)),
      // 유전자검사 개체
      this.geneDetailRepository
        .createQueryBuilder('gene')
        .select('DISTINCT gene.cowId', 'cowId')
        .where('gene.delDt IS NULL')
        .getRawMany()
        .then(rows => rows.map((r: { cowId: string }) => r.cowId).filter(Boolean)),
      // 번식능력검사 개체
      this.mptRepository
        .createQueryBuilder('mpt')
        .select('DISTINCT mpt.cowId', 'cowId')
        .where('mpt.delDt IS NULL')
        .getRawMany()
        .then(rows => rows.map((r: { cowId: string }) => r.cowId).filter(Boolean)),
    ]);

    const genomeSet = new Set(genomeCowIds);
    const geneSet = new Set(geneCowIds);
    const mptSet = new Set(mptCowIds);

    // 3. 모든 개체 정보 조회 (cowId로 농가 매핑)
    const allCows = await this.cowRepository.find({
      where: { delDt: IsNull() },
      select: ['cowId', 'cowBirthDt', 'cowSex', 'fkFarmNo'],
    });

    const cowFarmMap = new Map<string, number>();
    const cowInfoMap = new Map<string, { cowBirthDt: Date | null; cowSex: string | null }>();
    for (const cow of allCows) {
      if (cow.cowId && cow.fkFarmNo) {
        cowFarmMap.set(cow.cowId, cow.fkFarmNo);
        cowInfoMap.set(cow.cowId, { cowBirthDt: cow.cowBirthDt, cowSex: cow.cowSex });
      }
    }

    // 4. 농가별 집계
    const farmSummaries: FarmTestSummaryDto[] = [];

    for (const farm of farms) {
      const farmNo = farm.pkFarmNo;
      const farmCowIds = new Set<string>();

      // 해당 농가의 개체 필터링
      for (const [cowId, fNo] of cowFarmMap.entries()) {
        if (fNo === farmNo) {
          // 검사 받은 개체만 추가
          if (genomeSet.has(cowId) || geneSet.has(cowId) || mptSet.has(cowId)) {
            farmCowIds.add(cowId);
          }
        }
      }

      // 개체별 검사 상세
      const cows: CowTestDetailDto[] = [];
      let genomeCowCount = 0;
      let geneCowCount = 0;
      let mptCowCount = 0;
      let genomeOnly = 0;
      let geneOnly = 0;
      let mptOnly = 0;
      let genomeAndGene = 0;
      let genomeAndMpt = 0;
      let geneAndMpt = 0;
      let allThree = 0;
      let totalTests = 0;

      for (const cowId of farmCowIds) {
        const hasGenome = genomeSet.has(cowId);
        const hasGene = geneSet.has(cowId);
        const hasMpt = mptSet.has(cowId);
        const cowInfo = cowInfoMap.get(cowId);

        const testTypes: string[] = [];
        if (hasGenome) testTypes.push('유전체');
        if (hasGene) testTypes.push('유전자');
        if (hasMpt) testTypes.push('번식능력');

        // cowBirthDt 포맷 처리 (Date 객체 또는 문자열)
        let birthDtStr: string | null = null;
        if (cowInfo?.cowBirthDt) {
          if (cowInfo.cowBirthDt instanceof Date) {
            birthDtStr = cowInfo.cowBirthDt.toISOString().split('T')[0];
          } else {
            birthDtStr = String(cowInfo.cowBirthDt).split('T')[0];
          }
        }

        cows.push({
          cowId,
          cowBirthDt: birthDtStr,
          cowSex: cowInfo?.cowSex || null,
          hasGenome,
          hasGene,
          hasMpt,
          testCount: testTypes.length,
          testTypes,
        });

        // 검사별 카운트
        if (hasGenome) genomeCowCount++;
        if (hasGene) geneCowCount++;
        if (hasMpt) mptCowCount++;
        totalTests += testTypes.length;

        // 중복 검사 조합별 카운트
        if (hasGenome && hasGene && hasMpt) {
          allThree++;
        } else if (hasGenome && hasGene && !hasMpt) {
          genomeAndGene++;
        } else if (hasGenome && !hasGene && hasMpt) {
          genomeAndMpt++;
        } else if (!hasGenome && hasGene && hasMpt) {
          geneAndMpt++;
        } else if (hasGenome && !hasGene && !hasMpt) {
          genomeOnly++;
        } else if (!hasGenome && hasGene && !hasMpt) {
          geneOnly++;
        } else if (!hasGenome && !hasGene && hasMpt) {
          mptOnly++;
        }
      }

      // testCount 내림차순, cowId 오름차순 정렬
      cows.sort((a, b) => {
        if (b.testCount !== a.testCount) return b.testCount - a.testCount;
        return a.cowId.localeCompare(b.cowId);
      });

      farmSummaries.push({
        farmNo,
        farmerName: farm.farmerName || null,
        regionSi: farm.regionSi || null,
        genomeCowCount,
        geneCowCount,
        mptCowCount,
        genomeOnly,
        geneOnly,
        mptOnly,
        genomeAndGene,
        genomeAndMpt,
        geneAndMpt,
        allThree,
        totalCows: farmCowIds.size,
        totalTests,
        cows,
      });
    }

    // 검사 개체가 있는 농가만 필터링
    const activeFarms = farmSummaries.filter(f => f.totalCows > 0);

    // 5. 전체 집계 계산
    const allTestedCowIds = new Set([...genomeCowIds, ...geneCowIds, ...mptCowIds]);

    let totalGenomeOnly = 0;
    let totalGeneOnly = 0;
    let totalMptOnly = 0;
    let totalGenomeAndGene = 0;
    let totalGenomeAndMpt = 0;
    let totalGeneAndMpt = 0;
    let totalAllThree = 0;
    let totalTestsSum = 0;

    for (const cowId of allTestedCowIds) {
      const hasGenome = genomeSet.has(cowId);
      const hasGene = geneSet.has(cowId);
      const hasMpt = mptSet.has(cowId);

      let testCount = 0;
      if (hasGenome) testCount++;
      if (hasGene) testCount++;
      if (hasMpt) testCount++;
      totalTestsSum += testCount;

      if (hasGenome && hasGene && hasMpt) {
        totalAllThree++;
      } else if (hasGenome && hasGene && !hasMpt) {
        totalGenomeAndGene++;
      } else if (hasGenome && !hasGene && hasMpt) {
        totalGenomeAndMpt++;
      } else if (!hasGenome && hasGene && hasMpt) {
        totalGeneAndMpt++;
      } else if (hasGenome && !hasGene && !hasMpt) {
        totalGenomeOnly++;
      } else if (!hasGenome && hasGene && !hasMpt) {
        totalGeneOnly++;
      } else if (!hasGenome && !hasGene && hasMpt) {
        totalMptOnly++;
      }
    }

    return {
      totalFarms: activeFarms.length,
      totalCows: allTestedCowIds.size,
      totalTests: totalTestsSum,
      genomeCowCount: genomeCowIds.length,
      geneCowCount: geneCowIds.length,
      mptCowCount: mptCowIds.length,
      genomeOnly: totalGenomeOnly,
      geneOnly: totalGeneOnly,
      mptOnly: totalMptOnly,
      genomeAndGene: totalGenomeAndGene,
      genomeAndMpt: totalGenomeAndMpt,
      geneAndMpt: totalGeneAndMpt,
      allThree: totalAllThree,
      farms: activeFarms,
    };
  }
}
