import { AppDataSource } from "../database/data-source";
import { Profile } from "../entities/Profile";
import { PostRetireToExprofile } from "../controllers/ExRetirementController";
import { Between, MoreThanOrEqual } from "typeorm";

const BATCH_SIZE = 100;
const CONCURRENT_PER_BATCH = 10; // ส่ง parallel ทีละ 10 คนในแต่ละ batch

export class RetirementService {
  private profileRepository = AppDataSource.getRepository(Profile);

  /**
   * Cronjob สำหรับส่งข้อมูลผู้เกษียณไปยังระบบพ้นราชการ (Exprofile)
   * ทำงานเวลา 04:30:00 ของทุกวันที่ 1 ตุลาคม
   *
   * รายละเอียด:
   * - Query profiles ที่ leaveDate = วันที่ 1 ตุลาคมของปีนั้น และ leaveType = "RETIRE"
   * - Batch ทีละ 100 records
   * - Concurrent ทีละ 10 คน (parallel) ในแต่ละ batch
   * - ถ้า fail ให้ log error แล้วทำคนต่อไป
   */
  async cronjobPostRetireToExprofile(): Promise<{
    success: number;
    failed: number;
    failedProfiles: Array<{ id: string; name: string; error: string }>;
  }> {
    const result = {
      success: 0,
      failed: 0,
      failedProfiles: [] as Array<{ id: string; name: string; error: string }>,
    };

    try {
      // หาวันที่ 1 ตุลาคมของปีปัจจุบัน
      const now = new Date();
      const currentYear = now.getFullYear();

      // สร้างวันที่ 1 ตุลาคมของปีปัจจุบัน (เวลา 00:00:00)
      const startDate = new Date(currentYear, 9, 1, 0, 0, 0); // Month 9 = October (0-indexed)
      const endDate = new Date(currentYear, 9, 1, 23, 59, 59);

      // Query profiles ที่ leaveDate อยู่ในวันที่ 1 ตุลาคม และ leaveType = "RETIRE"
      const profiles = await this.profileRepository.find({
        where: [
          { leaveDate: Between(startDate, endDate), leaveType: "RETIRE" as any },
          { leaveDate: MoreThanOrEqual(startDate), leaveType: "RETIRE" as any },
        ],
        relations: ["posLevel", "posType"],
      });

      // Filter เอาเฉพาะวันที่ 1 ตุลาคมเท่านั้น
      const filteredProfiles = profiles.filter((p) => {
        if (!p.leaveDate) return false;
        const leaveDate = new Date(p.leaveDate);
        return (
          leaveDate.getFullYear() === currentYear &&
          leaveDate.getMonth() === 9 && // October
          leaveDate.getDate() === 1
        );
      });

      if (filteredProfiles.length === 0) {
        return result;
      }

      // แบ่ง batch ทีละ 100 records
      for (let i = 0; i < filteredProfiles.length; i += BATCH_SIZE) {
        const batch = filteredProfiles.slice(i, i + BATCH_SIZE);

        // แบ่งเป็น chunk เล็กๆ ทีละ CONCURRENT_PER_BATCH เพื่อส่ง parallel
        for (let j = 0; j < batch.length; j += CONCURRENT_PER_BATCH) {
          const chunk = batch.slice(j, j + CONCURRENT_PER_BATCH);

          // ส่ง parallel ในแต่ละ chunk
          await Promise.all(
            chunk.map(async (profile) => {
              try {
                await this.postSingleProfileToExprofile(profile);
                result.success++;
              } catch (error: any) {
                result.failed++;
                const errorInfo = {
                  id: profile.id,
                  name: `${profile.prefix}${profile.firstName} ${profile.lastName}`,
                  error: error.message || String(error),
                };
                result.failedProfiles.push(errorInfo);
              }
            }),
          );
        }
      }
    } catch (error: any) {
      // Log error but don't throw - allow cronjob to complete with partial results
      console.error("[cronjobPostRetireToExprofile] Error:", error);
      // Return current results instead of throwing
      return result;
    }

    return result;
  }

  /**
   * ส่งข้อมูล profile ไปยัง Exprofile
   */
  private async postSingleProfileToExprofile(profile: Profile): Promise<void> {
    if (!profile.leaveDate) {
      return;
    }

    if (!profile.citizenId) {
      return;
    }

    const retireDate = new Date(profile.leaveDate);
    const retireYear = retireDate.getFullYear();

    // Validate date is valid
    if (isNaN(retireYear) || retireYear < 2000) {
      throw new Error(`Invalid leaveDate for profile ${profile.id}: ${profile.leaveDate}`);
    }

    // ส่งไปยัง Exprofile
    await PostRetireToExprofile(
      null,
      profile.citizenId,
      profile.prefix || "",
      profile.firstName || "",
      profile.lastName || "",
      retireYear.toString(),
      profile.position || "",
      profile.posType?.posTypeName || "",
      profile.posLevel?.posLevelName || "",
      retireDate,
      profile.org || "",
      profile.leaveReason || "เกษียณอายุราชการ",
    );
  }
}
