import { Controller, Get, Post, Route, Tags, Body, Path, Response, Patch, Query } from "tsoa";
import { OrgRevision } from "../entities/OrgRevision";
import { AppDataSource } from "../database/data-source";
import HttpSuccess from "../interfaces/http-success";
import HttpError from "../interfaces/http-error";
import HttpStatusCode from "../interfaces/http-status";
import { Brackets, In, IsNull, LessThanOrEqual, MoreThanOrEqual, Not } from "typeorm";
import { OrgRoot } from "../entities/OrgRoot";
import { PosMaster } from "../entities/PosMaster";
import { calculateRetireDate } from "../interfaces/utils";
import { EmployeePosMaster } from "../entities/EmployeePosMaster";
import { Profile } from "../entities/Profile";
import { ProfileEmployee } from "../entities/ProfileEmployee";
import HttpStatus from "../interfaces/http-status";
import { ProfileAssessment } from "../entities/ProfileAssessment";
import { log } from "console";
import { format } from "path";
import { viewProfileEvaluation } from "../entities/view/viewProfileEvaluation";
import { viewPosMaster } from "../entities/view/viewPosMaster";
import { viewProfileEmployeeEvaluation } from "../entities/view/viewProfileEmployeeEvaluation";
import Extension from "../interfaces/extension";
import { resetPassword } from "../keycloak";
import { viewEmployeePosMaster } from "../entities/view/viewEmployeePosMaster";
import { EmployeePosDict } from "../entities/EmployeePosDict";
import { ProfileSalary } from "../entities/ProfileSalary";
import { ProfileInsignia } from "../entities/ProfileInsignia";
import { PosMasterHistory } from "../entities/PosMasterHistory";
import {
  ProfileAbsentLate,
  CreateProfileAbsentLate,
  CreateProfileAbsentLateBatch,
} from "../entities/ProfileAbsentLate";
import { ProfileAbsentLateHistory } from "../entities/ProfileAbsentLateHistory";
import {
  ProfileEmployeeAbsentLate,
  CreateProfileEmployeeAbsentLate,
  CreateProfileEmployeeAbsentLateBatch,
} from "../entities/ProfileEmployeeAbsentLate";
import { ProfileEmployeeAbsentLateHistory } from "../entities/ProfileEmployeeAbsentLateHistory";
@Route("api/v1/org/unauthorize")
@Tags("OrganizationUnauthorize")
@Response(
  HttpStatusCode.INTERNAL_SERVER_ERROR,
  "เกิดข้อผิดพลาด ไม่สามารถแสดงรายการได้ กรุณาลองใหม่ในภายหลัง",
)
export class OrganizationUnauthorizeController extends Controller {
  private orgRevisionRepository = AppDataSource.getRepository(OrgRevision);
  private orgRootRepository = AppDataSource.getRepository(OrgRoot);
  private profileRepo = AppDataSource.getRepository(Profile);
  private profileEmpRepo = AppDataSource.getRepository(ProfileEmployee);
  private profileAssessmentRepo = AppDataSource.getRepository(ProfileAssessment);
  private viewProfileEvaluationRepo = AppDataSource.getRepository(viewProfileEvaluation);
  private viewProfileEmployeeEvaluationRepo = AppDataSource.getRepository(
    viewProfileEmployeeEvaluation,
  );
  private employeePosDictRepository = AppDataSource.getRepository(EmployeePosDict);
  private posMasterRepository = AppDataSource.getRepository(PosMaster);
  private empPosMasterRepository = AppDataSource.getRepository(EmployeePosMaster);
  private salaryRepo = AppDataSource.getRepository(ProfileSalary);
  private posMasterHistoryRepository = AppDataSource.getRepository(PosMasterHistory);
  private insigniaRepo = AppDataSource.getRepository(ProfileInsignia);
  private absentLateRepo = AppDataSource.getRepository(ProfileAbsentLate);
  private absentLateHistoryRepo = AppDataSource.getRepository(ProfileAbsentLateHistory);
  private empAbsentLateRepo = AppDataSource.getRepository(ProfileEmployeeAbsentLate);
  private empAbsentLateHistoryRepo = AppDataSource.getRepository(ProfileEmployeeAbsentLateHistory);
  @Post("user/reset-password")
  async forgetPassword(
    @Body()
    body: {
      username: string;
    },
  ) {
    const result = await resetPassword(body.username);
    if (!result) {
      throw new Error("Failed. Cannot change password.");
    }
    return result;
  }

  /**
   * API รายชื่อราชการที่เลื่อนเงินเดือน (unauthorize)
   *
   * @summary ORG_072 - รายชื่อราชการที่เลื่อนเงินเดือน #76 (unauthorize)
   *
   */
  @Post("salary/gen")
  async salaryGen(
    @Body()
    body: {
      page: number;
      pageSize: number;
      keyword?: string;
      year: number;
      period: string;
    },
  ) {
    const findRevision = await this.orgRevisionRepository.findOne({
      where: { orgRevisionIsCurrent: true },
    });
    if (!findRevision) {
      throw new HttpError(HttpStatusCode.NOT_FOUND, "not found. OrgRevision");
    }

    const [findPosMaster, total] = await AppDataSource.getRepository(PosMaster)
      .createQueryBuilder("posMaster")
      .leftJoinAndSelect("posMaster.current_holder", "current_holder")
      .leftJoinAndSelect("posMaster.orgRoot", "orgRoot")
      .leftJoinAndSelect("posMaster.orgChild1", "orgChild1")
      .leftJoinAndSelect("posMaster.orgChild2", "orgChild2")
      .leftJoinAndSelect("posMaster.orgChild3", "orgChild3")
      .leftJoinAndSelect("posMaster.orgChild4", "orgChild4")
      .leftJoinAndSelect("posMaster.positions", "positions")
      .leftJoinAndSelect("positions.posExecutive", "posExecutive")
      .leftJoinAndSelect("current_holder.profileSalary", "profileSalary")
      .leftJoinAndSelect("current_holder.profileDisciplines", "profileDisciplines")
      .leftJoinAndSelect("current_holder.profileLeaves", "profileLeaves")
      .leftJoinAndSelect("current_holder.profileAssessments", "profileAssessments")
      .leftJoinAndSelect("current_holder.posLevel", "posLevel")
      .leftJoinAndSelect("current_holder.posType", "posType")
      .where({
        orgRevisionId: findRevision?.id,
        current_holderId: Not(IsNull()),
        // orgRootId: In([
        //   "4b574414-5faa-438c-829a-3c6444582cfd",
        //   "f4aae002-1c03-4ba2-b70b-64b261fc52fa",
        //   "1e8dba2f-b7d1-43c8-b06a-9b240414fd2b",
        //   "57477ae7-9de8-49cf-af2f-709cfd21dcb5",
        //   "a356d732-4a7f-4329-8c55-075290e3b533",
        //   "a2c0c2b3-c4ca-4451-8e52-04a9e4b02459",
        // ]),
      })
      .andWhere(
        new Brackets((qb) => {
          qb.where(
            body.keyword != null && body.keyword != ""
              ? "current_holder.prefix LIKE :keyword"
              : "1=1",
            {
              keyword: `%${body.keyword}%`,
            },
          )
            .orWhere(
              body.keyword != null && body.keyword != ""
                ? "current_holder.firstName LIKE :keyword"
                : "1=1",
              {
                keyword: `%${body.keyword}%`,
              },
            )
            .orWhere(
              body.keyword != null && body.keyword != ""
                ? "current_holder.lastName LIKE :keyword"
                : "1=1",
              {
                keyword: `%${body.keyword}%`,
              },
            )
            .orWhere(
              body.keyword != null && body.keyword != ""
                ? "current_holder.position LIKE :keyword"
                : "1=1",
              {
                keyword: `%${body.keyword}%`,
              },
            )

            .orWhere(
              body.keyword != null && body.keyword != ""
                ? "current_holder.citizenId LIKE :keyword"
                : "1=1",
              {
                keyword: `%${body.keyword}%`,
              },
            )
            .orWhere(
              body.keyword != null && body.keyword != ""
                ? "posType.posTypeName LIKE :keyword"
                : "1=1",
              {
                keyword: `%${body.keyword}%`,
              },
            )
            .orWhere(
              body.keyword != null && body.keyword != ""
                ? "posLevel.posLevelName LIKE :keyword"
                : "1=1",
              {
                keyword: `%${body.keyword}%`,
              },
            );
        }),
      )
      .orderBy("current_holder.citizenId", "ASC")
      .skip((body.page - 1) * body.pageSize)
      .take(body.pageSize)
      .getManyAndCount();
    if (!findPosMaster) {
      throw new HttpError(HttpStatusCode.NOT_FOUND, "not found. PosMaster");
    }
    
    const formattedData = findPosMaster.map((item) => {
      let orgShortName = "";

      if (item.orgChild1Id === null) {
        orgShortName = item.orgRoot?.orgRootShortName;
      } else if (item.orgChild2Id === null) {
        orgShortName = item.orgChild1?.orgChild1ShortName;
      } else if (item.orgChild3Id === null) {
        orgShortName = item.orgChild2?.orgChild2ShortName;
      } else if (item.orgChild4Id === null) {
        orgShortName = item.orgChild3?.orgChild3ShortName;
      } else {
        orgShortName = item.orgChild4?.orgChild4ShortName;
      }
      const posExecutive =
        item.positions == null ||
        item.positions?.find((position) => position.positionIsSelected == true) == null ||
        item.positions?.find((position) => position.positionIsSelected == true)?.posExecutive ==
          null ||
        item.positions?.find((position) => position.positionIsSelected == true)?.posExecutive
          ?.posExecutiveName == null
          ? null
          : item.positions?.find((position) => position.positionIsSelected == true)?.posExecutive
              .posExecutiveName;

      // const amount =
      //   item.current_holder == null || item.current_holder.profileSalary.length == 0
      //     ? null
      //     : item.current_holder.profileSalary.sort((a: any, b: any) => b.date - a.date)[0].amount;
      const amount = item.current_holder ? item.current_holder.amount : null;
      let datePeriodStart = new Date(
        `${new Date().getFullYear()}-${String(new Date().getMonth() + 1).padStart(2, "0")}-${String(new Date().getDate() + 1).padStart(2, "0")}T00:00:00.000Z`,
      );
      let datePeriodEnd = new Date(
        `${new Date().getFullYear()}-${String(new Date().getMonth() + 1).padStart(2, "0")}-${String(new Date().getDate() + 1).padStart(2, "0")}T00:00:00.000Z`,
      );
      if (body.period.toLocaleUpperCase() == "APR") {
        datePeriodStart = new Date(`${body.year}-03-31T00:00:00.000Z`);
        datePeriodEnd = new Date(`${body.year}-03-31T00:00:00.000Z`);
      }
      if (body.period.toLocaleUpperCase() == "OCT") {
        datePeriodStart = new Date(`${body.year}-09-30T00:00:00.000Z`);
        datePeriodEnd = new Date(`${body.year}-09-30T00:00:00.000Z`);
      }
      datePeriodStart = new Date(
        new Date(datePeriodStart.setDate(datePeriodStart.getDate() + 1)).setMonth(
          datePeriodStart.getMonth() - 6,
        ),
      );
      const specialPosition = item.positions.find(
        (position) => position.positionIsSelected === true,
      );
      const isSpecial = specialPosition ? specialPosition.isSpecial : null;

      const latestProfileAssessment = item.current_holder.profileAssessments
        ? item.current_holder.profileAssessments.sort((a: any, b: any) => b.date - a.date)[0]
        : null;
      const pointSum = latestProfileAssessment
        ? `(${this.textPointSummaryKpi(latestProfileAssessment.pointSum)})${latestProfileAssessment.pointSum}`
        : null;
      return {
        id: item.id,
        profileId: item.current_holder.id,
        prefix: item.current_holder.prefix,
        firstName: item.current_holder.firstName,
        lastName: item.current_holder.lastName,
        citizenId: item.current_holder.citizenId,
        posMasterNoPrefix: item.posMasterNoPrefix,
        posMasterNo: item.posMasterNo,
        posMasterNoSuffix: item.posMasterNoSuffix,
        orgShortName: orgShortName,
        position: item.current_holder.position,
        posType:
          item.current_holder.posType == null ? null : item.current_holder.posType.posTypeName,
        posLevel:
          item.current_holder.posLevel == null ? null : item.current_holder.posLevel.posLevelName,
        posExecutive: posExecutive,
        amount: amount ? amount : null,
        rootId: item.orgRootId,
        root: item.orgRoot?.orgRootName ? item.orgRoot.orgRootName : null,
        rootOrder: item.orgRoot?.orgRootOrder ? item.orgRoot.orgRootOrder : null,
        child1Id: item.orgChild1Id,
        child1: item.orgChild1?.orgChild1Name ? item.orgChild1.orgChild1Name : null,
        child1Order: item.orgChild1?.orgChild1Order ? item.orgChild1.orgChild1Order : null,
        child2Id: item.orgChild2Id,
        child2: item.orgChild2?.orgChild2Name ? item.orgChild2.orgChild2Name : null,
        child2Order: item.orgChild2?.orgChild2Order ? item.orgChild2.orgChild2Order : null,
        child3Id: item.orgChild3Id,
        child3: item.orgChild3?.orgChild3Name ? item.orgChild3.orgChild3Name : null,
        child3Order: item.orgChild3?.orgChild3Order ? item.orgChild3.orgChild3Order : null,
        child4Id: item.orgChild4Id,
        child4: item.orgChild4?.orgChild4Name ? item.orgChild4.orgChild4Name : null,
        child4Order: item.orgChild4?.orgChild4Order ? item.orgChild4.orgChild4Order : null,
        result: pointSum,
        duration: null,
        isPunish:
          item.current_holder.profileDisciplines.filter(
            (x: any) =>
              new Date(
                `${new Date(x.date).getFullYear()}-${String(new Date(x.date).getMonth() + 1).padStart(2, "0")}-${String(new Date(x.date).getDate() + 1).padStart(2, "0")}T00:00:00.000Z`,
              ) >= datePeriodStart &&
              new Date(
                `${new Date(x.date).getFullYear()}-${String(new Date(x.date).getMonth() + 1).padStart(2, "0")}-${String(new Date(x.date).getDate() + 1).padStart(2, "0")}T00:00:00.000Z`,
              ) <= datePeriodEnd,
          ).length > 0
            ? false
            : true,
        isSuspension: item.current_holder.dateRetire == null ? false : true,
        isAbsent: item.current_holder.profileDisciplines.length > 0 ? true : false,
        isLeave: item.current_holder.profileLeaves.length > 0 ? true : false,
        isRetired:
          item.current_holder.birthDate == null ||
          calculateRetireDate(item.current_holder.birthDate).getFullYear() != body.year
            ? false
            : true,
        isSpecial: isSpecial,
      };
    });
    return new HttpSuccess({ data: formattedData, total: total });
  }

  /**
   * API TEST รายชื่อราชการที่เลื่อนเงินเดือน (unauthorize)
   *
   * @summary TEST รายชื่อราชการที่เลื่อนเงินเดือน #76 (unauthorize)
   *
   */
  @Post("new-salary/gen")
  async newSalaryGen(
    @Body()
    body: {
      page: number;
      pageSize: number;
      keyword?: string;
      year: number;
      period: string;
    },
  ) {
    const findRevision = await this.orgRevisionRepository.findOne({
      where: { orgRevisionIsCurrent: true },
    });
    if (!findRevision) {
      throw new HttpError(HttpStatusCode.NOT_FOUND, "not found. OrgRevision");
    }
    //.chin
    // const rootIds = [
    //   "d7e98989-b5ce-47d6-93c3-ab63ed486348",
    //   "e0545eca-5d0a-4a1c-8bbd-e3e25c2521db",
    //   "26989ffa-d5ab-4bbd-ac97-130646cd1da6",
    //   "6f9b30e1-757a-40d5-b053-61eb1b91c0f0",
    //   "eaf65f33-25e9-4956-9dba-5d909f5eb595",
    //   "a3efed2c-3f4b-476d-95e6-9f7e0585ae25",
    // ];
    //.me
    // const rootIds = [
    //   "b89a4467-7ee3-4706-8db7-f366555f826c",
    //   "585648a9-e634-43fc-9360-5fd4189136ab",
    //   "d6e3daa0-284a-428f-aa43-0750fa74e974",
    //   "ed3ddcfb-f882-4499-817b-aff73e5be87c",
    //   "f8ce98ca-a691-4c89-abde-875f559afb3a",
    // ];

    const [findPosMaster, total] = await AppDataSource.getRepository(viewPosMaster)
      .createQueryBuilder("viewPosMaster")
      .where({orgRevisionId: findRevision?.id})
      .andWhere({positionIsSelected: true})
      // .andWhere("viewPosMaster.rootId IN (:...rootIds)", { rootIds })
      .andWhere(
        new Brackets((qb) => {
          qb.where(
            body.keyword != null && body.keyword != ""
              ? "prefix LIKE :keyword"
              : "1=1",
            {
              keyword: `%${body.keyword}%`,
            },
          )
            .orWhere(
              body.keyword != null && body.keyword != ""
                ? "firstName LIKE :keyword"
                : "1=1",
              {
                keyword: `%${body.keyword}%`,
              },
            )
            .orWhere(
              body.keyword != null && body.keyword != ""
                ? "lastName LIKE :keyword"
                : "1=1",
              {
                keyword: `%${body.keyword}%`,
              },
            )
            .orWhere(
              body.keyword != null && body.keyword != ""
                ? "position LIKE :keyword"
                : "1=1",
              {
                keyword: `%${body.keyword}%`,
              },
            )

            .orWhere(
              body.keyword != null && body.keyword != ""
                ? "citizenId LIKE :keyword"
                : "1=1",
              {
                keyword: `%${body.keyword}%`,
              },
            )
            .orWhere(
              body.keyword != null && body.keyword != ""
                ? "posTypeName LIKE :keyword"
                : "1=1",
              {
                keyword: `%${body.keyword}%`,
              },
            )
            .orWhere(
              body.keyword != null && body.keyword != ""
                ? "posLevelName LIKE :keyword"
                : "1=1",
              {
                keyword: `%${body.keyword}%`,
              },
            );
        }),
      )
      .orderBy("citizenId", "ASC")
      .skip((body.page - 1) * body.pageSize)
      .take(body.pageSize)
      .getManyAndCount();
    if (!findPosMaster) {
      throw new HttpError(HttpStatusCode.NOT_FOUND, "not found. PosMaster");
    }

    const profileAssessment = await this.profileAssessmentRepo.findOne(
      {
        where:{
          profileId: In(findPosMaster.map((item) => item.current_holderId)),
          year: body.year.toString(),
          pointSum: MoreThanOrEqual(90),
          period: body.period.toLocaleUpperCase(),
          isDeleted: false
        }
      }
    );
    
    const formattedData = findPosMaster.map((item) => {
      let orgShortName = "";

      if (item.orgChild1Id === null) {
        orgShortName = item?.orgRootShortName;
      } else if (item.orgChild2Id === null) {
        orgShortName = item?.orgChild1ShortName;
      } else if (item.orgChild3Id === null) {
        orgShortName = item?.orgChild2ShortName;
      } else if (item.orgChild4Id === null) {
        orgShortName = item?.orgChild3ShortName;
      } else {
        orgShortName = item?.orgChild4ShortName;
      }
     //  const posExecutive =
     //    item.positions == null ||
     //    item.positions?.find((position) => position.positionIsSelected == true) == null ||
     //    item.positions?.find((position) => position.positionIsSelected == true)?.posExecutive ==
     //      null ||
     //    item.positions?.find((position) => position.positionIsSelected == true)?.posExecutive
     //      ?.posExecutiveName == null
     //      ? null
     //      : item.positions?.find((position) => position.positionIsSelected == true)?.posExecutive
     //          .posExecutiveName;


      let datePeriodStart = new Date(
        `${new Date().getFullYear()}-${String(new Date().getMonth() + 1).padStart(2, "0")}-${String(new Date().getDate() + 1).padStart(2, "0")}T00:00:00.000Z`,
      );
      let datePeriodEnd = new Date(
        `${new Date().getFullYear()}-${String(new Date().getMonth() + 1).padStart(2, "0")}-${String(new Date().getDate() + 1).padStart(2, "0")}T00:00:00.000Z`,
      );
      if (body.period.toLocaleUpperCase() == "APR") {
        datePeriodStart = new Date(`${body.year}-03-31T00:00:00.000Z`);
        datePeriodEnd = new Date(`${body.year}-03-31T00:00:00.000Z`);
      }
      if (body.period.toLocaleUpperCase() == "OCT") {
        datePeriodStart = new Date(`${body.year}-09-30T00:00:00.000Z`);
        datePeriodEnd = new Date(`${body.year}-09-30T00:00:00.000Z`);
      }
      datePeriodStart = new Date(
        new Date(datePeriodStart.setDate(datePeriodStart.getDate() + 1)).setMonth(
          datePeriodStart.getMonth() - 6,
        ),
      );
     //  const specialPosition = item.positions.find(
     //    (position) => position.positionIsSelected === true,
     //  );
     //  const isSpecial = specialPosition ? specialPosition.isSpecial : null;

     
      const pointSum = item.pointSum
        ? `(${this.textPointSummaryKpi(item.pointSum)})${item.pointSum}` //่join ธรรมดาดึง row ล่าสุดอยู่แล้ว
        : null;
      return {
        id: item.id,
        profileId: item.current_holderId,
        prefix: item.prefix,
        firstName: item.firstName,
        lastName: item.lastName,
        citizenId: item.citizenId,
        posMasterNoPrefix: item.posMasterNoPrefix,
        posMasterNo: item.posMasterNo,
        posMasterNoSuffix: item.posMasterNoSuffix,
        orgShortName: orgShortName,
        position: item.position,
        posType: item.posTypeName,
        posLevel: item.posLevelName,
        posExecutive: item.posExecutiveName,
        positionExecutiveField: item.positionExecutiveField,
        positionArea: item.positionArea,
        amount: item.amount,
        rootId: item.orgRootId,
        root: item.orgRootName,
        rootOrder: item.orgRootOrder,
        child1Id: item.orgChild1Id,
        child1: item.orgChild1Name,
        child1Order: item.orgChild1Order,
        child2Id: item.orgChild2Id,
        child2: item.orgChild2Name,
        child2Order: item.orgChild2Order,
        child3Id: item.orgChild3Id,
        child3: item.orgChild3Name,
        child3Order: item.orgChild3Order,
        child4Id: item.orgChild4Id,
        child4: item.orgChild4Name,
        child4Order: item.orgChild4Order,
        result: pointSum,
        duration: null,
        isPunish:
         new Date(
           `${new Date(item.disCriplineDate).getFullYear()}-${String(new Date(item.disCriplineDate).getMonth() + 1).padStart(2, "0")}-${String(new Date(item.disCriplineDate).getDate() + 1).padStart(2, "0")}T00:00:00.000Z`,
         ) >= datePeriodStart &&
         new Date(
           `${new Date(item.disCriplineDate).getFullYear()}-${String(new Date(item.disCriplineDate).getMonth() + 1).padStart(2, "0")}-${String(new Date(item.disCriplineDate).getDate() + 1).padStart(2, "0")}T00:00:00.000Z`,
         ) <= datePeriodEnd
           ? false
           : true,
        isSuspension: item.dateRetire == null ? false : true,
        isAbsent: item.profileDisciplineId ? true : false,
        isLeave: item.profileLeaveId ? true : false,
        isRetired:
          item.birthDate == null ||
          calculateRetireDate(item.birthDate).getFullYear() != body.year
            ? false
            : true,
        //  isSpecial: isSpecial,
        isGood: profileAssessment?.profileId?.includes(item.current_holderId) ? true : false,
      };
    });
    return new HttpSuccess({ data: formattedData, total: total });
  }
  

  /**
   * API รายชื่อราชการที่เลื่อนเงินเดือน (unauthorize)
   *
   * @summary ORG_072 - รายชื่อราชการที่เลื่อนเงินเดือน #76 (unauthorize)
   *
   */
  @Post("salary/employee/gen")
  async salaryEmployeeGen(
    @Body()
    body: {
      page: number;
      pageSize: number;
      keyword?: string;
      year: number;
      period: string;
    },
  ) {
    const findRevision = await this.orgRevisionRepository.findOne({
      where: { orgRevisionIsCurrent: true },
    });
    if (!findRevision) {
      throw new HttpError(HttpStatusCode.NOT_FOUND, "not found. OrgRevision");
    }

    const [findPosMaster, total] = await AppDataSource.getRepository(EmployeePosMaster)
      .createQueryBuilder("employeePosMaster")
      .leftJoinAndSelect("employeePosMaster.current_holder", "current_holder")
      .leftJoinAndSelect("employeePosMaster.orgRoot", "orgRoot")
      .leftJoinAndSelect("employeePosMaster.orgChild1", "orgChild1")
      .leftJoinAndSelect("employeePosMaster.orgChild2", "orgChild2")
      .leftJoinAndSelect("employeePosMaster.orgChild3", "orgChild3")
      .leftJoinAndSelect("employeePosMaster.orgChild4", "orgChild4")
      .leftJoinAndSelect("employeePosMaster.positions", "positions")
      .leftJoinAndSelect("current_holder.profileSalary", "profileSalary")
      .leftJoinAndSelect("current_holder.profileDisciplines", "profileDisciplines")
      .leftJoinAndSelect("current_holder.profileLeaves", "profileLeaves")
      .leftJoinAndSelect("current_holder.profileAssessments", "profileAssessments")
      .leftJoinAndSelect("current_holder.posLevel", "posLevel")
      .leftJoinAndSelect("current_holder.posType", "posType")
      .where({
        orgRevisionId: findRevision?.id,
        current_holderId: Not(IsNull()),
      })
      .andWhere(
        new Brackets((qb) => {
          qb.where(
            body.keyword != null && body.keyword != ""
              ? "current_holder.prefix LIKE :keyword"
              : "1=1",
            {
              keyword: `%${body.keyword}%`,
            },
          )
            .orWhere(
              body.keyword != null && body.keyword != ""
                ? "current_holder.firstName LIKE :keyword"
                : "1=1",
              {
                keyword: `%${body.keyword}%`,
              },
            )
            .orWhere(
              body.keyword != null && body.keyword != ""
                ? "current_holder.lastName LIKE :keyword"
                : "1=1",
              {
                keyword: `%${body.keyword}%`,
              },
            )
            .orWhere(
              body.keyword != null && body.keyword != ""
                ? "current_holder.position LIKE :keyword"
                : "1=1",
              {
                keyword: `%${body.keyword}%`,
              },
            )

            .orWhere(
              body.keyword != null && body.keyword != ""
                ? "current_holder.citizenId LIKE :keyword"
                : "1=1",
              {
                keyword: `%${body.keyword}%`,
              },
            )
            .orWhere(
              body.keyword != null && body.keyword != ""
                ? "posType.posTypeName LIKE :keyword"
                : "1=1",
              {
                keyword: `%${body.keyword}%`,
              },
            )
            .orWhere(
              body.keyword != null && body.keyword != ""
                ? "posLevel.posLevelName LIKE :keyword"
                : "1=1",
              {
                keyword: `%${body.keyword}%`,
              },
            );
        }),
      )
      .orderBy("current_holder.citizenId", "ASC")
      .skip((body.page - 1) * body.pageSize)
      .take(body.pageSize)
      .getManyAndCount();
    if (!findPosMaster) {
      throw new HttpError(HttpStatusCode.NOT_FOUND, "not found. PosMaster");
    }

    const formattedData = findPosMaster.map((item) => {
      let orgShortName = "";

      if (item.orgChild1Id === null) {
        orgShortName = item.orgRoot?.orgRootShortName;
      } else if (item.orgChild2Id === null) {
        orgShortName = item.orgChild1?.orgChild1ShortName;
      } else if (item.orgChild3Id === null) {
        orgShortName = item.orgChild2?.orgChild2ShortName;
      } else if (item.orgChild4Id === null) {
        orgShortName = item.orgChild3?.orgChild3ShortName;
      } else {
        orgShortName = item.orgChild4?.orgChild4ShortName;
      }

      // const amount =
      //   item.current_holder == null || item.current_holder.profileSalary.length == 0
      //     ? null
      //     : item.current_holder.profileSalary.sort((a: any, b: any) => b.date - a.date)[0].amount;
      const amount = item.current_holder ? item.current_holder.amount : null;
      let datePeriodStart = new Date(
        `${new Date().getFullYear()}-${String(new Date().getMonth() + 1).padStart(2, "0")}-${String(new Date().getDate() + 1).padStart(2, "0")}T00:00:00.000Z`,
      );
      let datePeriodEnd = new Date(
        `${new Date().getFullYear()}-${String(new Date().getMonth() + 1).padStart(2, "0")}-${String(new Date().getDate() + 1).padStart(2, "0")}T00:00:00.000Z`,
      );
      if (body.period.toLocaleUpperCase() == "APR") {
        datePeriodStart = new Date(`${body.year}-03-31T00:00:00.000Z`);
        datePeriodEnd = new Date(`${body.year}-03-31T00:00:00.000Z`);
      }
      if (body.period.toLocaleUpperCase() == "OCT") {
        datePeriodStart = new Date(`${body.year}-09-30T00:00:00.000Z`);
        datePeriodEnd = new Date(`${body.year}-09-30T00:00:00.000Z`);
      }
      datePeriodStart = new Date(
        new Date(datePeriodStart.setDate(datePeriodStart.getDate() + 1)).setMonth(
          datePeriodStart.getMonth() - 6,
        ),
      );
      const latestProfileAssessment = item.current_holder.profileAssessments
        ? item.current_holder.profileAssessments.sort((a: any, b: any) => b.date - a.date)[0]
        : null;
      const pointSum = latestProfileAssessment
        ? `(${this.textPointSummaryKpi(latestProfileAssessment.pointSum)})${latestProfileAssessment.pointSum}`
        : null;
      return {
        profileId: item.current_holder.id,
        salaryLevel: item.current_holder.salaryLevel,
        group: item.current_holder.group,
        prefix: item.current_holder.prefix,
        firstName: item.current_holder.firstName,
        lastName: item.current_holder.lastName,
        citizenId: item.current_holder.citizenId,
        posMasterNoPrefix: item.posMasterNoPrefix,
        posMasterNo: item.posMasterNo,
        posMasterNoSuffix: item.posMasterNoSuffix,
        orgShortName: orgShortName,
        position: item.current_holder.position,
        posType:
          item.current_holder.posType == null ? null : item.current_holder.posType.posTypeName,
        posTypeShort:
          item.current_holder.posType == null ? null : item.current_holder.posType.posTypeShortName,
        posLevel:
          item.current_holder.posLevel == null ? null : item.current_holder.posLevel.posLevelName,
        amount: amount ? amount : null,
        rootId: item.orgRootId,
        root: item.orgRoot?.orgRootName ? item.orgRoot.orgRootName : null,
        rootOrder: item.orgRoot?.orgRootOrder ? item.orgRoot.orgRootOrder : null,
        child1Id: item.orgChild1Id,
        child1: item.orgChild1?.orgChild1Name ? item.orgChild1.orgChild1Name : null,
        child1Order: item.orgChild1?.orgChild1Order ? item.orgChild1.orgChild1Order : null,
        child2Id: item.orgChild2Id,
        child2: item.orgChild2?.orgChild2Name ? item.orgChild2.orgChild2Name : null,
        child2Order: item.orgChild2?.orgChild2Order ? item.orgChild2.orgChild2Order : null,
        child3Id: item.orgChild3Id,
        child3: item.orgChild3?.orgChild3Name ? item.orgChild3.orgChild3Name : null,
        child3Order: item.orgChild3?.orgChild3Order ? item.orgChild3.orgChild3Order : null,
        child4Id: item.orgChild4Id,
        child4: item.orgChild4?.orgChild4Name ? item.orgChild4.orgChild4Name : null,
        child4Order: item.orgChild4?.orgChild4Order ? item.orgChild4.orgChild4Order : null,
        result: pointSum,
        duration: null,
        isPunish:
          item.current_holder.profileDisciplines.filter(
            (x: any) =>
              new Date(
                `${new Date(x.date).getFullYear()}-${String(new Date(x.date).getMonth() + 1).padStart(2, "0")}-${String(new Date(x.date).getDate() + 1).padStart(2, "0")}T00:00:00.000Z`,
              ) >= datePeriodStart &&
              new Date(
                `${new Date(x.date).getFullYear()}-${String(new Date(x.date).getMonth() + 1).padStart(2, "0")}-${String(new Date(x.date).getDate() + 1).padStart(2, "0")}T00:00:00.000Z`,
              ) <= datePeriodEnd,
          ).length > 0
            ? false
            : true,
        isSuspension: item.current_holder.dateRetire == null ? false : true,
        isAbsent: item.current_holder.profileDisciplines.length > 0 ? true : false,
        isLeave: item.current_holder.profileLeaves.length > 0 ? true : false,
        isRetired:
          item.current_holder.birthDate == null ||
          calculateRetireDate(item.current_holder.birthDate).getFullYear() != body.year
            ? false
            : true,
      };
    });
    return new HttpSuccess({ data: formattedData, total: total });
  }

  /**
   * API รายชื่อราชการที่เลื่อนเงินเดือน (unauthorize)
   *
   * @summary ORG_072 - รายชื่อราชการที่เลื่อนเงินเดือน #76 (unauthorize)
   *
   */
  @Post("new-salary/employee/gen")
  async newSalaryEmployeeGen(
    @Body()
    body: {
      page: number;
      pageSize: number;
      keyword?: string;
      year: number;
      period: string;
    },
  ) {
    const findRevision = await this.orgRevisionRepository.findOne({
      where: { orgRevisionIsCurrent: true },
    });
    if (!findRevision) {
      throw new HttpError(HttpStatusCode.NOT_FOUND, "not found. OrgRevision");
    }
    //.chin
    // const rootIds = [
    //   "d7e98989-b5ce-47d6-93c3-ab63ed486348",
    //   "e0545eca-5d0a-4a1c-8bbd-e3e25c2521db",
    //   "26989ffa-d5ab-4bbd-ac97-130646cd1da6",
    //   "6f9b30e1-757a-40d5-b053-61eb1b91c0f0",
    //   "eaf65f33-25e9-4956-9dba-5d909f5eb595",
    //   "a3efed2c-3f4b-476d-95e6-9f7e0585ae25",
    // ];

    //.me
    // const rootIds = [
    //   "b89a4467-7ee3-4706-8db7-f366555f826c",
    //   "585648a9-e634-43fc-9360-5fd4189136ab",
    //   "d6e3daa0-284a-428f-aa43-0750fa74e974",
    //   "ed3ddcfb-f882-4499-817b-aff73e5be87c",
    //   "f8ce98ca-a691-4c89-abde-875f559afb3a",
    // ];

    const [findPosMaster, total] = await AppDataSource.getRepository(viewEmployeePosMaster)
    .createQueryBuilder("viewEmployeePosMaster")
      .where({
        orgRevisionId: findRevision?.id,
      })
      // .andWhere("viewEmployeePosMaster.rootId IN (:...rootIds)", { rootIds })
      .andWhere(
        new Brackets((qb) => {
          qb.where(
            body.keyword != null && body.keyword != ""
              ? "prefix LIKE :keyword"
              : "1=1",
            {
              keyword: `%${body.keyword}%`,
            },
          )
            .orWhere(
              body.keyword != null && body.keyword != ""
                ? "firstName LIKE :keyword"
                : "1=1",
              {
                keyword: `%${body.keyword}%`,
              },
            )
            .orWhere(
              body.keyword != null && body.keyword != ""
                ? "lastName LIKE :keyword"
                : "1=1",
              {
                keyword: `%${body.keyword}%`,
              },
            )
            .orWhere(
              body.keyword != null && body.keyword != ""
                ? "position LIKE :keyword"
                : "1=1",
              {
                keyword: `%${body.keyword}%`,
              },
            )

            .orWhere(
              body.keyword != null && body.keyword != ""
                ? "citizenId LIKE :keyword"
                : "1=1",
              {
                keyword: `%${body.keyword}%`,
              },
            )
            .orWhere(
              body.keyword != null && body.keyword != ""
                ? "posTypeName LIKE :keyword"
                : "1=1",
              {
                keyword: `%${body.keyword}%`,
              },
            )
            .orWhere(
              body.keyword != null && body.keyword != ""
                ? "posLevelName LIKE :keyword"
                : "1=1",
              {
                keyword: `%${body.keyword}%`,
              },
            );
        }),
      )
      .orderBy("citizenId", "ASC")
      .skip((body.page - 1) * body.pageSize)
      .take(body.pageSize)
      .getManyAndCount();
    if (!findPosMaster) {
      throw new HttpError(HttpStatusCode.NOT_FOUND, "not found. PosMaster");
    }

    const profileAssessment = await this.profileAssessmentRepo.findOne(
      {
        where:{
          profileEmployeeId: In(findPosMaster.map((item) => item.current_holderId)),
          year: body.year.toString(),
          pointSum: MoreThanOrEqual(90),
          period: body.period.toLocaleUpperCase(),
          isDeleted: false
        }
      }
    );

    const formattedData = findPosMaster.map((item) => {
      let orgShortName = "";

      if (item.orgChild1Id === null) {
        orgShortName = item?.orgRootShortName;
      } else if (item.orgChild2Id === null) {
        orgShortName = item?.orgChild1ShortName;
      } else if (item.orgChild3Id === null) {
        orgShortName = item?.orgChild2ShortName;
      } else if (item.orgChild4Id === null) {
        orgShortName = item?.orgChild3ShortName;
      } else {
        orgShortName = item?.orgChild4ShortName;
      }

      // const amount =
      //   item.current_holder == null || item.current_holder.profileSalary.length == 0
      //     ? null
      //     : item.current_holder.profileSalary.sort((a: any, b: any) => b.date - a.date)[0].amount;
      const amount = item ? item.amount : null;
      let datePeriodStart = new Date(
        `${new Date().getFullYear()}-${String(new Date().getMonth() + 1).padStart(2, "0")}-${String(new Date().getDate() + 1).padStart(2, "0")}T00:00:00.000Z`,
      );
      let datePeriodEnd = new Date(
        `${new Date().getFullYear()}-${String(new Date().getMonth() + 1).padStart(2, "0")}-${String(new Date().getDate() + 1).padStart(2, "0")}T00:00:00.000Z`,
      );
      if (body.period.toLocaleUpperCase() == "APR") {
        datePeriodStart = new Date(`${body.year}-03-31T00:00:00.000Z`);
        datePeriodEnd = new Date(`${body.year}-03-31T00:00:00.000Z`);
      }
      if (body.period.toLocaleUpperCase() == "OCT") {
        datePeriodStart = new Date(`${body.year}-09-30T00:00:00.000Z`);
        datePeriodEnd = new Date(`${body.year}-09-30T00:00:00.000Z`);
      }
      datePeriodStart = new Date(
        new Date(datePeriodStart.setDate(datePeriodStart.getDate() + 1)).setMonth(
          datePeriodStart.getMonth() - 6,
        ),
      );
      // const latestProfileAssessment = item.current_holder.profileAssessments
      //   ? item.current_holder.profileAssessments.sort((a: any, b: any) => b.date - a.date)[0]
      //   : null;
      // const pointSum = latestProfileAssessment
      //   ? `(${this.textPointSummaryKpi(latestProfileAssessment.pointSum)})${latestProfileAssessment.pointSum}`
      //   : null;
      const pointSum = item.pointSum
        ? `(${this.textPointSummaryKpi(item.pointSum)})${item.pointSum}` //่join ธรรมดาดึง row ล่าสุดอยู่แล้ว
        : null;
      return {
        profileId: item.current_holderId,
        salaryLevel: item.salaryLevel,
        group: item.group,
        prefix: item.prefix,
        firstName: item.firstName,
        lastName: item.lastName,
        citizenId: item.citizenId,
        posMasterNoPrefix: item.posMasterNoPrefix,
        posMasterNo: item.posMasterNo,
        posMasterNoSuffix: item.posMasterNoSuffix,
        orgShortName: orgShortName,
        position: item.position,
        posType: item.posTypeName,
        posTypeShort: item.posTypeShortName,
        posLevel: item.posLevelName,
        amount: amount ? amount : null,
        rootId: item.orgRootId,
        root: item?.orgRootName ? item.orgRootName : null,
        rootOrder: item?.orgRootOrder ? item.orgRootOrder : null,
        child1Id: item.orgChild1Id,
        child1: item?.orgChild1Name ? item.orgChild1Name : null,
        child1Order: item?.orgChild1Order ? item.orgChild1Order : null,
        child2Id: item.orgChild2Id,
        child2: item?.orgChild2Name ? item.orgChild2Name : null,
        child2Order: item?.orgChild2Order ? item.orgChild2Order : null,
        child3Id: item.orgChild3Id,
        child3: item?.orgChild3Name ? item.orgChild3Name : null,
        child3Order: item?.orgChild3Order ? item.orgChild3Order : null,
        child4Id: item.orgChild4Id,
        child4: item?.orgChild4Name ? item.orgChild4Name : null,
        child4Order: item?.orgChild4Order ? item.orgChild4Order : null,
        result: pointSum,
        duration: null,
        isPunish:
          new Date(
            `${new Date(item.disCriplineDate).getFullYear()}-${String(new Date(item.disCriplineDate).getMonth() + 1).padStart(2, "0")}-${String(new Date(item.disCriplineDate).getDate() + 1).padStart(2, "0")}T00:00:00.000Z`,
          ) >= datePeriodStart &&
          new Date(
            `${new Date(item.disCriplineDate).getFullYear()}-${String(new Date(item.disCriplineDate).getMonth() + 1).padStart(2, "0")}-${String(new Date(item.disCriplineDate).getDate() + 1).padStart(2, "0")}T00:00:00.000Z`,
          ) <= datePeriodEnd
            ? false
            : true,
        isSuspension: item.dateRetire == null ? false : true,
        isAbsent: item.profileDisciplineId ? true : false,
        isLeave: item.profileLeaveId ? true : false,
        isRetired:
          item.birthDate == null ||
          calculateRetireDate(item.birthDate).getFullYear() != body.year
            ? false
            : true,
        isGood: profileAssessment?.profileEmployeeId?.includes(item.current_holderId) ? true : false,
      };
    });
    return new HttpSuccess({ data: formattedData, total: total });
  }

  /**
   * API หาสำนักทั้งหมด (unauthorize)
   *
   * @summary หาสำนักทั้งหมด (unauthorize)
   *
   */
  @Get("active/root/id")
  async _GetActiveRootId() {
    try {
      const orgRevisionActive = await this.orgRevisionRepository.findOne({
        where: { orgRevisionIsCurrent: true, orgRevisionIsDraft: false },
      });
      if (!orgRevisionActive) {
        throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบโครงสร้างที่เผยแพร่อยู่ตอนนี้");
      }

      const data = await this.orgRootRepository.find({
        where: { orgRevisionId: orgRevisionActive.id },
      });
      return new HttpSuccess(
        data.map((x) => ({
          rootId: x.id,
          root: x.orgRootName,
          rootDnaId: x.ancestorDNA,
        })),
      );
    } catch (error) {
      return error;
    }
  }

  /**
   * API หา revision ล่าสุด (unauthorize)
   *
   * @summary หา revision ล่าสุด (unauthorize)
   *
   */
  @Get("revision/latest")
  async _salaryGen() {
    const findRevision = await this.orgRevisionRepository.findOne({
      where: { orgRevisionIsCurrent: true },
    });
    if (!findRevision) {
      throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบโครงสร้างล่าสุด");
    }
    return new HttpSuccess(findRevision.id);
  }

  /**
   * API Get Profile จาก profile id
   *
   * @summary API Get Profile จาก profile id
   *
   * @param {string} profileId  Id profile
   */
  @Get("profile/{profileId}")
  async GetProfileByProfileIdAsync(@Path() profileId: string) {
    const profile = await this.profileRepo.findOne({
      relations: [
        "posLevel",
        "posType",
        "current_holders",
        "current_holders.orgRevision",
        "current_holders.orgRoot",
        "current_holders.orgChild1",
        "current_holders.orgChild2",
        "current_holders.orgChild3",
        "current_holders.orgChild4",
      ],
      where: { id: profileId },
    });

    if (!profile) {
      const profile = await this.profileEmpRepo.findOne({
        relations: [
          "posLevel",
          "posType",
          "current_holders",
          "current_holders.orgRevision",
          "current_holders.orgRoot",
          "current_holders.orgChild1",
          "current_holders.orgChild2",
          "current_holders.orgChild3",
          "current_holders.orgChild4",
        ],
        where: { id: profileId },
      });
      if (!profile) throw new HttpError(HttpStatus.NOT_FOUND, "ไม่พบข้อมูล");

      const [latestSalary, latestInsignia] = await Promise.all([
        this.salaryRepo.findOne({
          where: { profileEmployeeId: profile.id },
          order: { commandDateAffect: "DESC" },
        }),
        this.insigniaRepo.findOne({
          where: { profileEmployeeId: profile.id, isDeleted: false },
          order: { receiveDate: "DESC" },
        }),
      ]);
      
      const org = {
        root:
          profile?.current_holders?.find(
            (x) =>
              x.orgRevision?.orgRevisionIsDraft == false &&
              x.orgRevision?.orgRevisionIsCurrent == true,
          )?.orgRoot?.id ?? null,
        child1:
          profile?.current_holders?.find(
            (x) =>
              x.orgRevision?.orgRevisionIsDraft == false &&
              x.orgRevision?.orgRevisionIsCurrent == true,
          )?.orgChild1?.id ?? null,
        child2:
          profile?.current_holders?.find(
            (x) =>
              x.orgRevision?.orgRevisionIsDraft == false &&
              x.orgRevision?.orgRevisionIsCurrent == true,
          )?.orgChild2?.id ?? null,
        child3:
          profile?.current_holders?.find(
            (x) =>
              x.orgRevision?.orgRevisionIsDraft == false &&
              x.orgRevision?.orgRevisionIsCurrent == true,
          )?.orgChild3?.id ?? null,
        child4:
          profile?.current_holders?.find(
            (x) =>
              x.orgRevision?.orgRevisionIsDraft == false &&
              x.orgRevision?.orgRevisionIsCurrent == true,
          )?.orgChild4?.id ?? null,
      };
      let fullname = "";
      let pos = await this.empPosMasterRepository.findOne({
        relations: ["current_holder"],
        where: {
          current_holder: Not(IsNull()),
          orgRevision: {
            orgRevisionIsCurrent: true,
            orgRevisionIsDraft: false,
          },
          isDirector: true,
          orgRootId: org?.root ?? "",
          orgChild1Id: org?.child1 ?? "",
          orgChild2Id: org?.child2 ?? "",
          orgChild3Id: org?.child3 ?? "",
          orgChild4Id: org?.child4 ?? "",
        },
      });

      if (pos) {
        fullname =
          pos.current_holder.prefix +
          pos.current_holder.firstName +
          " " +
          pos.current_holder.lastName;
      } else {
        let pos = await this.empPosMasterRepository.findOne({
          relations: ["current_holder"],
          where: {
            current_holder: Not(IsNull()),
            orgRevision: {
              orgRevisionIsCurrent: true,
              orgRevisionIsDraft: false,
            },
            isDirector: true,
            orgRootId: org?.root ?? "",
            orgChild1Id: org?.child1 ?? "",
            orgChild2Id: org?.child2 ?? "",
            orgChild3Id: org?.child3 ?? "",
            orgChild4Id: IsNull(),
          },
        });
        if (pos) {
          fullname =
            pos.current_holder.prefix +
            pos.current_holder.firstName +
            " " +
            pos.current_holder.lastName;
        } else {
          let pos = await this.empPosMasterRepository.findOne({
            relations: ["current_holder"],
            where: {
              current_holder: Not(IsNull()),
              orgRevision: {
                orgRevisionIsCurrent: true,
                orgRevisionIsDraft: false,
              },
              isDirector: true,
              orgRootId: org?.root ?? "",
              orgChild1Id: org?.child1 ?? "",
              orgChild2Id: org?.child2 ?? "",
              orgChild3Id: IsNull(),
              orgChild4Id: IsNull(),
            },
          });
          if (pos) {
            fullname =
              pos.current_holder.prefix +
              pos.current_holder.firstName +
              " " +
              pos.current_holder.lastName;
          } else {
            let pos = await this.empPosMasterRepository.findOne({
              relations: ["current_holder"],
              where: {
                current_holder: Not(IsNull()),
                orgRevision: {
                  orgRevisionIsCurrent: true,
                  orgRevisionIsDraft: false,
                },
                isDirector: true,
                orgRootId: org?.root ?? "",
                orgChild1Id: org?.child1 ?? "",
                orgChild2Id: IsNull(),
                orgChild3Id: IsNull(),
                orgChild4Id: IsNull(),
              },
            });
            if (pos) {
              fullname =
                pos.current_holder.prefix +
                pos.current_holder.firstName +
                " " +
                pos.current_holder.lastName;
            } else {
              let pos = await this.empPosMasterRepository.findOne({
                relations: ["current_holder"],
                where: {
                  current_holder: Not(IsNull()),
                  orgRevision: {
                    orgRevisionIsCurrent: true,
                    orgRevisionIsDraft: false,
                  },
                  orgRootId: org?.root ?? "",
                  orgChild1Id: IsNull(),
                  orgChild2Id: IsNull(),
                  orgChild3Id: IsNull(),
                  orgChild4Id: IsNull(),
                },
              });
              if (pos) {
                fullname =
                  pos.current_holder.prefix +
                  pos.current_holder.firstName +
                  " " +
                  pos.current_holder.lastName;
              } else {
                fullname = "";
              }
            }
          }
        }
      }

      const mapProfile = {
        id: profile.id,
        avatar: profile.avatar,
        avatarName: profile.avatarName,
        rank: profile.rank,
        prefix: profile.prefix,
        firstName: profile.firstName,
        lastName: profile.lastName,
        citizenId: profile.citizenId,
        position: profile.position,
        posLevelId: profile.posLevelId,
        email: profile.email,
        phone: profile.phone,
        keycloak: profile.keycloak,
        isProbation: profile.isProbation,
        isLeave: profile.isLeave,
        leaveReason: profile.leaveReason,
        dateRetire: profile.dateRetire,
        dateAppoint: profile.dateAppoint,
        dateRetireLaw: profile.dateRetireLaw,
        dateStart: profile.dateStart,
        govAgeAbsent: profile.govAgeAbsent,
        govAgePlus: profile.govAgePlus,
        birthDate: profile.birthDate ?? new Date(),
        reasonSameDate: profile.reasonSameDate,
        telephoneNumber: profile.phone,
        nationality: profile.nationality,
        gender: profile.gender,
        relationship: profile.relationship,
        religion: profile.religion,
        bloodGroup: profile.bloodGroup,
        registrationAddress: profile.registrationAddress,
        registrationProvinceId: profile.registrationProvinceId,
        registrationDistrictId: profile.registrationDistrictId,
        registrationSubDistrictId: profile.registrationSubDistrictId,
        registrationZipCode: profile.registrationZipCode,
        currentAddress: profile.currentAddress,
        currentProvinceId: profile.currentProvinceId,
        currentSubDistrictId: profile.currentSubDistrictId,
        currentZipCode: profile.currentZipCode,
        dutyTimeId: profile.dutyTimeId,
        dutyTimeEffectiveDate: profile.dutyTimeEffectiveDate,
        amount: profile.amount,
        positionSalaryAmount: profile.positionSalaryAmount,
        mouthSalaryAmount: profile.mouthSalaryAmount,
        root:
          profile?.current_holders?.find(
            (x) =>
              x.orgRevision?.orgRevisionIsDraft == false &&
              x.orgRevision?.orgRevisionIsCurrent == true,
          )?.orgRoot?.orgRootName ?? null,
        child1:
          profile?.current_holders?.find(
            (x) =>
              x.orgRevision?.orgRevisionIsDraft == false &&
              x.orgRevision?.orgRevisionIsCurrent == true,
          )?.orgChild1?.orgChild1Name ?? null,
        child2:
          profile?.current_holders?.find(
            (x) =>
              x.orgRevision?.orgRevisionIsDraft == false &&
              x.orgRevision?.orgRevisionIsCurrent == true,
          )?.orgChild2?.orgChild2Name ?? null,
        child3:
          profile?.current_holders?.find(
            (x) =>
              x.orgRevision?.orgRevisionIsDraft == false &&
              x.orgRevision?.orgRevisionIsCurrent == true,
          )?.orgChild3?.orgChild3Name ?? null,
        child4:
          profile?.current_holders?.find(
            (x) =>
              x.orgRevision?.orgRevisionIsDraft == false &&
              x.orgRevision?.orgRevisionIsCurrent == true,
          )?.orgChild4?.orgChild4Name ?? null,
        rootId:
          profile?.current_holders?.find(
            (x) =>
              x.orgRevision?.orgRevisionIsDraft == false &&
              x.orgRevision?.orgRevisionIsCurrent == true,
          )?.orgRootId ?? null,
        child1Id:
          profile?.current_holders?.find(
            (x) =>
              x.orgRevision?.orgRevisionIsDraft == false &&
              x.orgRevision?.orgRevisionIsCurrent == true,
          )?.orgChild1Id ?? null,
        child2Id:
          profile?.current_holders?.find(
            (x) =>
              x.orgRevision?.orgRevisionIsDraft == false &&
              x.orgRevision?.orgRevisionIsCurrent == true,
          )?.orgChild2Id ?? null,
        child3Id:
          profile?.current_holders?.find(
            (x) =>
              x.orgRevision?.orgRevisionIsDraft == false &&
              x.orgRevision?.orgRevisionIsCurrent == true,
          )?.orgChild3Id ?? null,
        child4Id:
          profile?.current_holders?.find(
            (x) =>
              x.orgRevision?.orgRevisionIsDraft == false &&
              x.orgRevision?.orgRevisionIsCurrent == true,
          )?.orgChild4Id ?? null,
        rootDnaId:
          profile?.current_holders?.find(
            (x) =>
              x.orgRevision?.orgRevisionIsDraft == false &&
              x.orgRevision?.orgRevisionIsCurrent == true,
          )?.orgRoot?.ancestorDNA ?? null,
        child1DnaId:
          profile?.current_holders?.find(
            (x) =>
              x.orgRevision?.orgRevisionIsDraft == false &&
              x.orgRevision?.orgRevisionIsCurrent == true,
          )?.orgChild3?.ancestorDNA ?? null,
        child2DnaId:
          profile?.current_holders?.find(
            (x) =>
              x.orgRevision?.orgRevisionIsDraft == false &&
              x.orgRevision?.orgRevisionIsCurrent == true,
          )?.orgChild2?.ancestorDNA ?? null,
        child3DnaId:
          profile?.current_holders?.find(
            (x) =>
              x.orgRevision?.orgRevisionIsDraft == false &&
              x.orgRevision?.orgRevisionIsCurrent == true,
          )?.orgChild3?.ancestorDNA ?? null,
        child4DnaId:
          profile?.current_holders?.find(
            (x) =>
              x.orgRevision?.orgRevisionIsDraft == false &&
              x.orgRevision?.orgRevisionIsCurrent == true,
          )?.orgChild4?.ancestorDNA ?? null,
        commander: fullname,
        posLevel:
          (profile.posType == null || profile.posType?.posTypeShortName == null
            ? ""
            : profile.posType?.posTypeShortName + " ") + (profile.posLevel?.posLevelName ?? ""),
        posType: profile.posType?.posTypeName ?? null,
        profileSalary: latestSalary ?? null,
        profileInsignia: latestInsignia ?? null,
        profileType: "EMPLOYEE",
      };

      return new HttpSuccess(mapProfile);
    }

    const [latestSalary, latestInsignia] = await Promise.all([
      this.salaryRepo.findOne({
        where: { profileId: profile.id },
        order: { commandDateAffect: "DESC" },
      }),
      this.insigniaRepo.findOne({
        where: { profileId: profile.id, isDeleted: false },
        order: { receiveDate: "DESC" },
      }),
    ]);

    const org = {
      root:
        profile?.current_holders?.find(
          (x) =>
            x.orgRevision?.orgRevisionIsDraft == false &&
            x.orgRevision?.orgRevisionIsCurrent == true,
        )?.orgRoot?.id ?? null,
      child1:
        profile?.current_holders?.find(
          (x) =>
            x.orgRevision?.orgRevisionIsDraft == false &&
            x.orgRevision?.orgRevisionIsCurrent == true,
        )?.orgChild1?.id ?? null,
      child2:
        profile?.current_holders?.find(
          (x) =>
            x.orgRevision?.orgRevisionIsDraft == false &&
            x.orgRevision?.orgRevisionIsCurrent == true,
        )?.orgChild2?.id ?? null,
      child3:
        profile?.current_holders?.find(
          (x) =>
            x.orgRevision?.orgRevisionIsDraft == false &&
            x.orgRevision?.orgRevisionIsCurrent == true,
        )?.orgChild3?.id ?? null,
      child4:
        profile?.current_holders?.find(
          (x) =>
            x.orgRevision?.orgRevisionIsDraft == false &&
            x.orgRevision?.orgRevisionIsCurrent == true,
        )?.orgChild4?.id ?? null,
    };

    let fullname = "";
    let pos = await this.posMasterRepository.findOne({
      relations: ["current_holder"],
      where: {
        current_holder: Not(IsNull()),
        orgRevision: {
          orgRevisionIsCurrent: true,
          orgRevisionIsDraft: false,
        },
        isDirector: true,
        orgRootId: org?.root ?? "",
        orgChild1Id: org?.child1 ?? "",
        orgChild2Id: org?.child2 ?? "",
        orgChild3Id: org?.child3 ?? "",
        orgChild4Id: org?.child4 ?? "",
      },
    });

    if (pos) {
      fullname =
        pos.current_holder.prefix +
        pos.current_holder.firstName +
        " " +
        pos.current_holder.lastName;
    } else {
      let pos = await this.posMasterRepository.findOne({
        relations: ["current_holder"],
        where: {
          current_holder: Not(IsNull()),
          orgRevision: {
            orgRevisionIsCurrent: true,
            orgRevisionIsDraft: false,
          },
          isDirector: true,
          orgRootId: org?.root ?? "",
          orgChild1Id: org?.child1 ?? "",
          orgChild2Id: org?.child2 ?? "",
          orgChild3Id: org?.child3 ?? "",
          orgChild4Id: IsNull(),
        },
      });
      if (pos) {
        fullname =
          pos.current_holder.prefix +
          pos.current_holder.firstName +
          " " +
          pos.current_holder.lastName;
      } else {
        let pos = await this.posMasterRepository.findOne({
          relations: ["current_holder"],
          where: {
            current_holder: Not(IsNull()),
            orgRevision: {
              orgRevisionIsCurrent: true,
              orgRevisionIsDraft: false,
            },
            isDirector: true,
            orgRootId: org?.root ?? "",
            orgChild1Id: org?.child1 ?? "",
            orgChild2Id: org?.child2 ?? "",
            orgChild3Id: IsNull(),
            orgChild4Id: IsNull(),
          },
        });
        if (pos) {
          fullname =
            pos.current_holder.prefix +
            pos.current_holder.firstName +
            " " +
            pos.current_holder.lastName;
        } else {
          let pos = await this.posMasterRepository.findOne({
            relations: ["current_holder"],
            where: {
              current_holder: Not(IsNull()),
              orgRevision: {
                orgRevisionIsCurrent: true,
                orgRevisionIsDraft: false,
              },
              isDirector: true,
              orgRootId: org?.root ?? "",
              orgChild1Id: org?.child1 ?? "",
              orgChild2Id: IsNull(),
              orgChild3Id: IsNull(),
              orgChild4Id: IsNull(),
            },
          });
          if (pos) {
            fullname =
              pos.current_holder.prefix +
              pos.current_holder.firstName +
              " " +
              pos.current_holder.lastName;
          } else {
            let pos = await this.posMasterRepository.findOne({
              relations: ["current_holder"],
              where: {
                current_holder: Not(IsNull()),
                orgRevision: {
                  orgRevisionIsCurrent: true,
                  orgRevisionIsDraft: false,
                },
                orgRootId: org?.root ?? "",
                orgChild1Id: IsNull(),
                orgChild2Id: IsNull(),
                orgChild3Id: IsNull(),
                orgChild4Id: IsNull(),
              },
            });
            if (pos) {
              fullname =
                pos.current_holder.prefix +
                pos.current_holder.firstName +
                " " +
                pos.current_holder.lastName;
            } else {
              fullname = "";
            }
          }
        }
      }
    }

    const mapProfile = {
      id: profile.id,
      avatar: profile.avatar,
      avatarName: profile.avatarName,
      rank: profile.rank,
      prefix: profile.prefix,
      firstName: profile.firstName,
      lastName: profile.lastName,
      citizenId: profile.citizenId,
      position: profile.position,
      posLevelId: profile.posLevelId,
      email: profile.email,
      phone: profile.phone,
      keycloak: profile.keycloak,
      isProbation: profile.isProbation,
      isLeave: profile.isLeave,
      leaveReason: profile.leaveReason,
      dateRetire: profile.dateRetire,
      dateAppoint: profile.dateAppoint,
      dateRetireLaw: profile.dateRetireLaw,
      dateStart: profile.dateStart,
      govAgeAbsent: profile.govAgeAbsent,
      govAgePlus: profile.govAgePlus,
      birthDate: profile.birthDate ?? new Date(),
      reasonSameDate: profile.reasonSameDate,
      telephoneNumber: profile.phone,
      nationality: profile.nationality,
      gender: profile.gender,
      relationship: profile.relationship,
      religion: profile.religion,
      bloodGroup: profile.bloodGroup,
      registrationAddress: profile.registrationAddress,
      registrationProvinceId: profile.registrationProvinceId,
      registrationDistrictId: profile.registrationDistrictId,
      registrationSubDistrictId: profile.registrationSubDistrictId,
      registrationZipCode: profile.registrationZipCode,
      currentAddress: profile.currentAddress,
      currentProvinceId: profile.currentProvinceId,
      currentSubDistrictId: profile.currentSubDistrictId,
      currentZipCode: profile.currentZipCode,
      dutyTimeId: profile.dutyTimeId,
      dutyTimeEffectiveDate: profile.dutyTimeEffectiveDate,
      amount: profile.amount,
      positionSalaryAmount: profile.positionSalaryAmount,
      mouthSalaryAmount: profile.mouthSalaryAmount,
      root:
        profile?.current_holders?.find(
          (x) =>
            x.orgRevision?.orgRevisionIsDraft == false &&
            x.orgRevision?.orgRevisionIsCurrent == true,
        )?.orgRoot?.orgRootName ?? null,
      child1:
        profile?.current_holders?.find(
          (x) =>
            x.orgRevision?.orgRevisionIsDraft == false &&
            x.orgRevision?.orgRevisionIsCurrent == true,
        )?.orgChild1?.orgChild1Name ?? null,
      child2:
        profile?.current_holders?.find(
          (x) =>
            x.orgRevision?.orgRevisionIsDraft == false &&
            x.orgRevision?.orgRevisionIsCurrent == true,
        )?.orgChild2?.orgChild2Name ?? null,
      child3:
        profile?.current_holders?.find(
          (x) =>
            x.orgRevision?.orgRevisionIsDraft == false &&
            x.orgRevision?.orgRevisionIsCurrent == true,
        )?.orgChild3?.orgChild3Name ?? null,
      child4:
        profile?.current_holders?.find(
          (x) =>
            x.orgRevision?.orgRevisionIsDraft == false &&
            x.orgRevision?.orgRevisionIsCurrent == true,
        )?.orgChild4?.orgChild4Name ?? null,
      rootId:
        profile?.current_holders?.find(
          (x) =>
            x.orgRevision?.orgRevisionIsDraft == false &&
            x.orgRevision?.orgRevisionIsCurrent == true,
        )?.orgRootId ?? null,
      child1Id:
        profile?.current_holders?.find(
          (x) =>
            x.orgRevision?.orgRevisionIsDraft == false &&
            x.orgRevision?.orgRevisionIsCurrent == true,
        )?.orgChild1Id ?? null,
      child2Id:
        profile?.current_holders?.find(
          (x) =>
            x.orgRevision?.orgRevisionIsDraft == false &&
            x.orgRevision?.orgRevisionIsCurrent == true,
        )?.orgChild2Id ?? null,
      child3Id:
        profile?.current_holders?.find(
          (x) =>
            x.orgRevision?.orgRevisionIsDraft == false &&
            x.orgRevision?.orgRevisionIsCurrent == true,
        )?.orgChild3Id ?? null,
      child4Id:
        profile?.current_holders?.find(
          (x) =>
            x.orgRevision?.orgRevisionIsDraft == false &&
            x.orgRevision?.orgRevisionIsCurrent == true,
        )?.orgChild4Id ?? null,
      rootDnaId:
        profile?.current_holders?.find(
          (x) =>
            x.orgRevision?.orgRevisionIsDraft == false &&
            x.orgRevision?.orgRevisionIsCurrent == true,
        )?.orgRoot?.ancestorDNA ?? null,
      child1DnaId:
        profile?.current_holders?.find(
          (x) =>
            x.orgRevision?.orgRevisionIsDraft == false &&
            x.orgRevision?.orgRevisionIsCurrent == true,
        )?.orgChild1?.ancestorDNA ?? null,
      child2DnaId:
        profile?.current_holders?.find(
          (x) =>
            x.orgRevision?.orgRevisionIsDraft == false &&
            x.orgRevision?.orgRevisionIsCurrent == true,
        )?.orgChild2?.ancestorDNA ?? null,
      child3DnaId:
        profile?.current_holders?.find(
          (x) =>
            x.orgRevision?.orgRevisionIsDraft == false &&
            x.orgRevision?.orgRevisionIsCurrent == true,
        )?.orgChild3?.ancestorDNA ?? null,
      child4DnaId:
        profile?.current_holders?.find(
          (x) =>
            x.orgRevision?.orgRevisionIsDraft == false &&
            x.orgRevision?.orgRevisionIsCurrent == true,
        )?.orgChild4?.ancestorDNA ?? null,
      commander: fullname,
      posLevel: profile.posLevel?.posLevelName ?? null,
      posType: profile.posType?.posTypeName ?? null,
      profileSalary: latestSalary ?? null,
      profileInsignia: latestInsignia ?? null,
      profileType: "OFFICER",
    };

    return new HttpSuccess(mapProfile);
  }

  /**
   * API หา user profile officer
   *
   * @summary หา user profile officer
   *
   */
  @Get("officer/{id}")
  async GetProfileById(@Path() id: string) {
    const findRevision = await this.orgRevisionRepository.findOne({
      where: { orgRevisionIsCurrent: true },
    });
    if (!findRevision) {
      throw new HttpError(HttpStatusCode.NOT_FOUND, "not found. OrgRevision");
    }

    const findProfile = await AppDataSource.getRepository(Profile)
      .createQueryBuilder("profile")
      .leftJoinAndSelect("profile.current_holders", "current_holders")
      .leftJoinAndSelect("current_holders.positions", "positions")
      .leftJoinAndSelect("positions.posExecutive", "posExecutive")
      .where({ id: id })
      .getOne();
    if (!findProfile) {
      throw new HttpError(HttpStatusCode.NOT_FOUND, "not found Profile");
    }

    const posExecutive =
      findProfile.current_holders == null ||
      findProfile.current_holders.length == 0 ||
      findProfile.current_holders.find((x) => x.orgRevisionId == findRevision.id) == null ||
      findProfile.current_holders.find((x) => x.orgRevisionId == findRevision.id)?.positions ==
        null ||
      findProfile.current_holders?.find((x) => x.orgRevisionId == findRevision.id)?.positions
        .length == 0 ||
      findProfile.current_holders
        .find((x) => x.orgRevisionId == findRevision.id)
        ?.positions?.find((position) => position.positionIsSelected == true) == null ||
      findProfile.current_holders
        .find((x) => x.orgRevisionId == findRevision.id)
        ?.positions?.find((position) => position.positionIsSelected == true)?.posExecutive ==
        null ||
      findProfile.current_holders
        .find((x) => x.orgRevisionId == findRevision.id)
        ?.positions?.find((position) => position.positionIsSelected == true)?.posExecutive
        ?.posExecutiveName == null
        ? null
        : findProfile.current_holders
            .find((x) => x.orgRevisionId == findRevision.id)
            ?.positions?.find((position) => position.positionIsSelected == true)?.posExecutive
            .posExecutiveName;
    const root =
      findProfile.current_holders == null ||
      findProfile.current_holders.length == 0 ||
      findProfile.current_holders.find((x) => x.orgRevisionId == findRevision.id) == null
        ? null
        : findProfile.current_holders.find((x) => x.orgRevisionId == findRevision.id)?.orgRoot;
    return new HttpSuccess({
      rootId: root == null ? null : root.id,
      root: root == null ? null : root.orgRootName,
      orgRootShortName: root == null ? null : root.orgRootShortName,
      orgRevisionId: findRevision.id,
      profileId: findProfile.id,
      type: "OFFICER",
      rank: findProfile.rank,
      prefix: findProfile.prefix,
      firstName: findProfile.firstName,
      lastName: findProfile.lastName,
      citizenId: findProfile.citizenId,
      position: findProfile.position,
      posExecutive: posExecutive,
      posLevelId: findProfile.posLevelId,
      posTypeId: findProfile.posTypeId,
    });
  }

  /**
   * API หา user profile employee
   *
   * @summary หา user profile employee
   *
   */
  @Get("employee/{id}")
  async GetProfileEmployeeById(@Path() id: string) {
    const findRevision = await this.orgRevisionRepository.findOne({
      where: { orgRevisionIsCurrent: true },
    });
    if (!findRevision) {
      throw new HttpError(HttpStatusCode.NOT_FOUND, "not found. OrgRevision");
    }

    const findProfile = await AppDataSource.getRepository(ProfileEmployee)
      .createQueryBuilder("profile")
      .leftJoinAndSelect("profile.current_holders", "current_holders")
      .leftJoinAndSelect("current_holders.positions", "positions")
      .leftJoinAndSelect("positions.posExecutive", "posExecutive")
      .where({ id: id })
      .getOne();
    if (!findProfile) {
      throw new HttpError(HttpStatusCode.NOT_FOUND, "not found Profile");
    }

    const root =
      findProfile.current_holders == null ||
      findProfile.current_holders.length == 0 ||
      findProfile.current_holders.find((x) => x.orgRevisionId == findRevision.id) == null
        ? null
        : findProfile.current_holders.find((x) => x.orgRevisionId == findRevision.id)?.orgRoot;

    return new HttpSuccess({
      rootId: root == null ? null : root.id,
      root: root == null ? null : root.orgRootName,
      orgRootShortName: root == null ? null : root.orgRootShortName,
      orgRevisionId: findRevision.id,
      profileId: findProfile.id,
      type: "OFFICER",
      rank: findProfile.rank,
      prefix: findProfile.prefix,
      firstName: findProfile.firstName,
      lastName: findProfile.lastName,
      citizenId: findProfile.citizenId,
      position: findProfile.position,
      posLevelId: findProfile.posLevelId,
      posTypeId: findProfile.posTypeId,
    });
  }

  /**
   * API หา user profile officer
   *
   * @summary หา user profile officer
   *
   */
  @Get("officer/citizen/{id}")
  async GetProfileByCitizenId(@Path() id: string) {
    const findRevision = await this.orgRevisionRepository.findOne({
      where: { orgRevisionIsCurrent: true },
    });
    if (!findRevision) {
      throw new HttpError(HttpStatusCode.NOT_FOUND, "not found. OrgRevision");
    }

    const findProfile = await AppDataSource.getRepository(Profile)
      .createQueryBuilder("profile")
      .leftJoinAndSelect("profile.current_holders", "current_holders")
      .leftJoinAndSelect("current_holders.orgRoot", "orgRoot")
      .leftJoinAndSelect("current_holders.orgChild1", "orgChild1")
      .leftJoinAndSelect("current_holders.orgChild2", "orgChild2")
      .leftJoinAndSelect("current_holders.orgChild3", "orgChild3")
      .leftJoinAndSelect("current_holders.orgChild4", "orgChild4")
      .leftJoinAndSelect("current_holders.positions", "positions")
      .leftJoinAndSelect("positions.posExecutive", "posExecutive")
      .where("current_holders.orgRevisionId = :orgRevisionId", { orgRevisionId: findRevision.id })
      .andWhere({ citizenId: id })
      .getOne();
    if (!findProfile) {
      throw new HttpError(HttpStatusCode.NOT_FOUND, "not found Profile");
    }

    const posExecutive =
      findProfile.current_holders == null ||
      findProfile.current_holders.length == 0 ||
      findProfile.current_holders.find((x) => x.orgRevisionId == findRevision.id) == null ||
      findProfile.current_holders.find((x) => x.orgRevisionId == findRevision.id)?.positions ==
        null ||
      findProfile.current_holders?.find((x) => x.orgRevisionId == findRevision.id)?.positions
        .length == 0 ||
      findProfile.current_holders
        .find((x) => x.orgRevisionId == findRevision.id)
        ?.positions?.find((position) => position.positionIsSelected == true) == null ||
      findProfile.current_holders
        .find((x) => x.orgRevisionId == findRevision.id)
        ?.positions?.find((position) => position.positionIsSelected == true)?.posExecutive ==
        null ||
      findProfile.current_holders
        .find((x) => x.orgRevisionId == findRevision.id)
        ?.positions?.find((position) => position.positionIsSelected == true)?.posExecutive
        ?.posExecutiveName == null
        ? null
        : findProfile.current_holders
            .find((x) => x.orgRevisionId == findRevision.id)
            ?.positions?.find((position) => position.positionIsSelected == true)?.posExecutive
            .posExecutiveName;
    const root =
      findProfile.current_holders == null ||
      findProfile.current_holders.length == 0 ||
      findProfile.current_holders.find((x) => x.orgRevisionId == findRevision.id) == null
        ? null
        : findProfile.current_holders.find((x) => x.orgRevisionId == findRevision.id)?.orgRoot;

    const child1 =
      findProfile.current_holders == null ||
      findProfile.current_holders.length == 0 ||
      findProfile.current_holders.find((x) => x.orgRevisionId == findRevision.id) == null
        ? null
        : findProfile.current_holders.find((x) => x.orgRevisionId == findRevision.id)?.orgChild1;

    const child2 =
      findProfile.current_holders == null ||
      findProfile.current_holders.length == 0 ||
      findProfile.current_holders.find((x) => x.orgRevisionId == findRevision.id) == null
        ? null
        : findProfile.current_holders.find((x) => x.orgRevisionId == findRevision.id)?.orgChild2;

    const child3 =
      findProfile.current_holders == null ||
      findProfile.current_holders.length == 0 ||
      findProfile.current_holders.find((x) => x.orgRevisionId == findRevision.id) == null
        ? null
        : findProfile.current_holders.find((x) => x.orgRevisionId == findRevision.id)?.orgChild3;

    const child4 =
      findProfile.current_holders == null ||
      findProfile.current_holders.length == 0 ||
      findProfile.current_holders.find((x) => x.orgRevisionId == findRevision.id) == null
        ? null
        : findProfile.current_holders.find((x) => x.orgRevisionId == findRevision.id)?.orgChild4;

    let _root = root?.orgRootName;
    let _child1 = child1?.orgChild1Name;
    let _child2 = child2?.orgChild2Name;
    let _child3 = child3?.orgChild3Name;
    let _child4 = child4?.orgChild4Name;

    return new HttpSuccess({
      rootId: root == null ? null : root.id,
      root: root == null ? null : root.orgRootName,
      orgRootShortName: root == null ? null : root.orgRootShortName,
      orgRevisionId: findRevision.id,
      profileId: findProfile.id,
      org:
        (_child4 == null ? "" : _child4 + "\n") +
        (_child3 == null ? "" : _child3 + "\n") +
        (_child2 == null ? "" : _child2 + "\n") +
        (_child1 == null ? "" : _child1 + "\n") +
        (_root == null ? "" : _root),
      type: "OFFICER",
      rank: findProfile.rank,
      prefix: findProfile.prefix,
      firstName: findProfile.firstName,
      lastName: findProfile.lastName,
      citizenId: findProfile.citizenId,
      position: findProfile.position,
      posExecutive: posExecutive,
      posLevelId: findProfile.posLevelId,
      posTypeId: findProfile.posTypeId,
    });
  }

  /**
   * API หา user profile employee
   *
   * @summary หา user profile employee
   *
   */
  @Get("employee/citizen/{id}")
  async GetProfileEmployeeByCitizenId(@Path() id: string) {
    const findRevision = await this.orgRevisionRepository.findOne({
      where: { orgRevisionIsCurrent: true },
    });
    if (!findRevision) {
      throw new HttpError(HttpStatusCode.NOT_FOUND, "not found. OrgRevision");
    }

    const findProfile = await AppDataSource.getRepository(ProfileEmployee)
      .createQueryBuilder("profile")
      .leftJoinAndSelect("profile.current_holders", "current_holders")
      .leftJoinAndSelect("current_holders.orgRoot", "orgRoot")
      .leftJoinAndSelect("current_holders.orgChild1", "orgChild1")
      .leftJoinAndSelect("current_holders.orgChild2", "orgChild2")
      .leftJoinAndSelect("current_holders.orgChild3", "orgChild3")
      .leftJoinAndSelect("current_holders.orgChild4", "orgChild4")
      .leftJoinAndSelect("current_holders.positions", "positions")
      // .leftJoinAndSelect("positions.posExecutive", "posExecutive")
      .where({ citizenId: id })
      .getOne();
    if (!findProfile) {
      throw new HttpError(HttpStatusCode.NOT_FOUND, "not found Profile");
    }

    const root =
      findProfile.current_holders == null ||
      findProfile.current_holders.length == 0 ||
      findProfile.current_holders.find((x) => x.orgRevisionId == findRevision.id) == null
        ? null
        : findProfile.current_holders.find((x) => x.orgRevisionId == findRevision.id)?.orgRoot;

    const child1 =
      findProfile.current_holders == null ||
      findProfile.current_holders.length == 0 ||
      findProfile.current_holders.find((x) => x.orgRevisionId == findRevision.id) == null
        ? null
        : findProfile.current_holders.find((x) => x.orgRevisionId == findRevision.id)?.orgChild1;

    const child2 =
      findProfile.current_holders == null ||
      findProfile.current_holders.length == 0 ||
      findProfile.current_holders.find((x) => x.orgRevisionId == findRevision.id) == null
        ? null
        : findProfile.current_holders.find((x) => x.orgRevisionId == findRevision.id)?.orgChild2;

    const child3 =
      findProfile.current_holders == null ||
      findProfile.current_holders.length == 0 ||
      findProfile.current_holders.find((x) => x.orgRevisionId == findRevision.id) == null
        ? null
        : findProfile.current_holders.find((x) => x.orgRevisionId == findRevision.id)?.orgChild3;

    const child4 =
      findProfile.current_holders == null ||
      findProfile.current_holders.length == 0 ||
      findProfile.current_holders.find((x) => x.orgRevisionId == findRevision.id) == null
        ? null
        : findProfile.current_holders.find((x) => x.orgRevisionId == findRevision.id)?.orgChild4;

    let _root = root?.orgRootName;
    let _child1 = child1?.orgChild1Name;
    let _child2 = child2?.orgChild2Name;
    let _child3 = child3?.orgChild3Name;
    let _child4 = child4?.orgChild4Name;

    return new HttpSuccess({
      rootId: root == null ? null : root.id,
      root: root == null ? null : root.orgRootName,
      orgRootShortName: root == null ? null : root.orgRootShortName,
      orgRevisionId: findRevision.id,
      profileId: findProfile.id,
      org:
        (_child4 == null ? "" : _child4 + "\n") +
        (_child3 == null ? "" : _child3 + "\n") +
        (_child2 == null ? "" : _child2 + "\n") +
        (_child1 == null ? "" : _child1 + "\n") +
        (_root == null ? "" : _root),
      type: "EMPLOYEE",
      rank: findProfile.rank,
      prefix: findProfile.prefix,
      firstName: findProfile.firstName,
      lastName: findProfile.lastName,
      citizenId: findProfile.citizenId,
      position: findProfile.position,
      posLevelId: findProfile.posLevelId,
      posTypeId: findProfile.posTypeId,
    });
  }

  /**
   * API หา user profile employee
   *
   * @summary หา user profile employee
   *
   */
  @Get("employee-prem/citizen/{id}")
  async GetProfileEmployeePremByCitizenId(@Path() id: string) {
    const findRevision = await this.orgRevisionRepository.findOne({
      where: { orgRevisionIsCurrent: true },
    });
    if (!findRevision) {
      throw new HttpError(HttpStatusCode.NOT_FOUND, "not found. OrgRevision");
    }

    const findProfile = await AppDataSource.getRepository(ProfileEmployee)
      .createQueryBuilder("profile")
      .leftJoinAndSelect("profile.current_holders", "current_holders")
      .leftJoinAndSelect("current_holders.orgRoot", "orgRoot")
      .leftJoinAndSelect("current_holders.orgChild1", "orgChild1")
      .leftJoinAndSelect("current_holders.orgChild2", "orgChild2")
      .leftJoinAndSelect("current_holders.orgChild3", "orgChild3")
      .leftJoinAndSelect("current_holders.orgChild4", "orgChild4")
      .leftJoinAndSelect("current_holders.positions", "positions")
      .where("current_holders.orgRevisionId = :orgRevisionId", { orgRevisionId: findRevision.id })
      // .leftJoinAndSelect("positions.posExecutive", "posExecutive")
      .andWhere({ citizenId: id, employeeClass: "PERM" })
      .getOne();
    if (!findProfile) {
      throw new HttpError(HttpStatusCode.NOT_FOUND, "not found Profile");
    }

    const root =
      findProfile.current_holders == null ||
      findProfile.current_holders.length == 0 ||
      findProfile.current_holders.find((x) => x.orgRevisionId == findRevision.id) == null
        ? null
        : findProfile.current_holders.find((x) => x.orgRevisionId == findRevision.id)?.orgRoot;

    const child1 =
      findProfile.current_holders == null ||
      findProfile.current_holders.length == 0 ||
      findProfile.current_holders.find((x) => x.orgRevisionId == findRevision.id) == null
        ? null
        : findProfile.current_holders.find((x) => x.orgRevisionId == findRevision.id)?.orgChild1;

    const child2 =
      findProfile.current_holders == null ||
      findProfile.current_holders.length == 0 ||
      findProfile.current_holders.find((x) => x.orgRevisionId == findRevision.id) == null
        ? null
        : findProfile.current_holders.find((x) => x.orgRevisionId == findRevision.id)?.orgChild2;

    const child3 =
      findProfile.current_holders == null ||
      findProfile.current_holders.length == 0 ||
      findProfile.current_holders.find((x) => x.orgRevisionId == findRevision.id) == null
        ? null
        : findProfile.current_holders.find((x) => x.orgRevisionId == findRevision.id)?.orgChild3;

    const child4 =
      findProfile.current_holders == null ||
      findProfile.current_holders.length == 0 ||
      findProfile.current_holders.find((x) => x.orgRevisionId == findRevision.id) == null
        ? null
        : findProfile.current_holders.find((x) => x.orgRevisionId == findRevision.id)?.orgChild4;

    let _root = root?.orgRootName;
    let _child1 = child1?.orgChild1Name;
    let _child2 = child2?.orgChild2Name;
    let _child3 = child3?.orgChild3Name;
    let _child4 = child4?.orgChild4Name;

    return new HttpSuccess({
      rootId: root == null ? null : root.id,
      root: root == null ? null : root.orgRootName,
      orgRootShortName: root == null ? null : root.orgRootShortName,
      orgRevisionId: findRevision.id,
      profileId: findProfile.id,
      org:
        (_child4 == null ? "" : _child4 + "\n") +
        (_child3 == null ? "" : _child3 + "\n") +
        (_child2 == null ? "" : _child2 + "\n") +
        (_child1 == null ? "" : _child1 + "\n") +
        (_root == null ? "" : _root),
      type: "EMPLOYEE",
      rank: findProfile.rank,
      prefix: findProfile.prefix,
      firstName: findProfile.firstName,
      lastName: findProfile.lastName,
      citizenId: findProfile.citizenId,
      position: findProfile.position,
      posLevelId: findProfile.posLevelId,
      posTypeId: findProfile.posTypeId,
    });
  }
  textPointSummaryKpi(val: number | undefined) {
    if (val == undefined || val == null) val = -1;
    if (val >= 0 && val <= 60) return "ต้องปรับปรุง";
    if (val >= 60 && val <= 69) return "พอใช้";
    if (val >= 70 && val <= 79) return "ดี";
    if (val >= 80 && val <= 89) return "ดีมาก";
    if (val >= 90 && val <= 100) return "ดีเด่น";
    if (val > 101) return "ดีเด่น";
    else return "-";
  }

  /**
   * API หาสำนักทั้งหมด
   *
   * @summary หาสำนักทั้งหมด
   *
   */
  @Get("active/root/all")
  async GetActiveRootAll() {
    const orgRevisionActive = await this.orgRevisionRepository.findOne({
      where: { orgRevisionIsCurrent: true, orgRevisionIsDraft: false },
    });
    if (!orgRevisionActive) {
      throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบโครงสร้างที่เผยแพร่อยู่ตอนนี้");
    }

    const data = await this.orgRootRepository.find({
      where: { orgRevisionId: orgRevisionActive.id },
    });
    return new HttpSuccess(data);
  }

  @Get("root/officer/{rootId}")
  async GetProfileByRootIdAsync(@Path() rootId: string) {
    const profiles = await this.profileRepo.find({
      relations: [
        "posLevel",
        "posType",
        "profileSalary",
        "profileInsignias",
        "profileInsignias.insignia",
        "profileDisciplines",
        "profileAssessments",
        "current_holders",
        "current_holders.orgRevision",
        "current_holders.orgRoot",
        "current_holders.orgChild1",
        "current_holders.orgChild2",
        "current_holders.orgChild3",
        "current_holders.orgChild4",
      ],
      where: { current_holders: { orgRootId: rootId } },
      order: {
        profileSalary: {
          commandDateAffect: "DESC",
        },
        profileInsignias: {
          receiveDate: "DESC",
        },
      },
    });

    const currentYear = new Date().getFullYear();
    const years = [currentYear, currentYear - 1, currentYear - 2, currentYear - 3, currentYear - 4];

    // APR Averages
    const aprAverages: { [year: number]: number | null } = {};
    const aprSums: { [year: number]: number } = {};
    const aprCounts: { [year: number]: number } = {};

    // OCT Averages
    const octAverages: { [year: number]: number | null } = {};
    const octSums: { [year: number]: number } = {};
    const octCounts: { [year: number]: number } = {};

    years.forEach((year) => {
      aprAverages[year] = null;
      aprSums[year] = 0;
      aprCounts[year] = 0;

      octAverages[year] = null;
      octSums[year] = 0;
      octCounts[year] = 0;
    });

    profiles.forEach((profile) => {
      const assessments = profile.profileAssessments || [];

      assessments.forEach((assessment) => {
        const year = Number(assessment.year);

        if (years.includes(year)) {
          if (assessment.period === "APR") {
            aprSums[year] += assessment.pointSum;
            aprCounts[year] += 1;
          }

          if (assessment.period === "OCT") {
            octSums[year] += assessment.pointSum;
            octCounts[year] += 1;
          }
        }
      });
    });

    years.forEach((year) => {
      aprAverages[year] = aprCounts[year] > 0 ? aprSums[year] / aprCounts[year] : null;
      octAverages[year] = octCounts[year] > 0 ? octSums[year] / octCounts[year] : null;
    });

    const findRevision = await this.orgRevisionRepository.findOne({
      where: { orgRevisionIsCurrent: true },
    });

    const mapProfile = profiles.map((profile) => {
      const shortName =
        profile.current_holders.length == 0
          ? null
          : profile.current_holders.find((x) => x.orgRevisionId == findRevision?.id) != null &&
              profile.current_holders.find((x) => x.orgRevisionId == findRevision?.id)?.orgChild4 !=
                null
            ? `${profile.current_holders.find((x) => x.orgRevisionId == findRevision?.id)?.orgChild4.orgChild4ShortName} ${profile.current_holders.find((x) => x.orgRevisionId == findRevision?.id)?.posMasterNo}`
            : profile.current_holders.find((x) => x.orgRevisionId == findRevision?.id) != null &&
                profile.current_holders.find((x) => x.orgRevisionId == findRevision?.id)
                  ?.orgChild3 != null
              ? `${profile.current_holders.find((x) => x.orgRevisionId == findRevision?.id)?.orgChild3.orgChild3ShortName} ${profile.current_holders.find((x) => x.orgRevisionId == findRevision?.id)?.posMasterNo}`
              : profile.current_holders.find((x) => x.orgRevisionId == findRevision?.id) != null &&
                  profile.current_holders.find((x) => x.orgRevisionId == findRevision?.id)
                    ?.orgChild2 != null
                ? `${profile.current_holders.find((x) => x.orgRevisionId == findRevision?.id)?.orgChild2.orgChild2ShortName} ${profile.current_holders.find((x) => x.orgRevisionId == findRevision?.id)?.posMasterNo}`
                : profile.current_holders.find((x) => x.orgRevisionId == findRevision?.id) !=
                      null &&
                    profile.current_holders.find((x) => x.orgRevisionId == findRevision?.id)
                      ?.orgChild1 != null
                  ? `${profile.current_holders.find((x) => x.orgRevisionId == findRevision?.id)?.orgChild1.orgChild1ShortName} ${profile.current_holders.find((x) => x.orgRevisionId == findRevision?.id)?.posMasterNo}`
                  : profile.current_holders.find((x) => x.orgRevisionId == findRevision?.id) !=
                        null &&
                      profile.current_holders.find((x) => x.orgRevisionId == findRevision?.id)
                        ?.orgRoot != null
                    ? `${profile.current_holders.find((x) => x.orgRevisionId == findRevision?.id)?.orgRoot.orgRootShortName} ${profile.current_holders.find((x) => x.orgRevisionId == findRevision?.id)?.posMasterNo}`
                    : null;

      return {
        id: profile.id,
        avatar: profile.avatar,
        avatarName: profile.avatarName,
        rank: profile.rank ?? "",
        prefix: profile.prefix ?? "",
        firstName: profile.firstName ?? "",
        lastName: profile.lastName ?? "",
        citizenId: profile.citizenId ?? "",
        position: profile.position ?? "",
        posLevelId: profile.posLevelId,
        posTypeId: profile.posTypeId,
        email: profile.email,
        phone: profile.phone,
        keycloak: profile.keycloak,
        isProbation: profile.isProbation,
        isLeave: profile.isLeave,
        leaveReason: profile.leaveReason,
        dateRetire: profile.dateRetire,
        dateAppoint: profile.dateAppoint,
        dateRetireLaw: profile.dateRetireLaw,
        dateStart: profile.dateStart,
        govAgeAbsent: profile.govAgeAbsent,
        govAgePlus: profile.govAgePlus,
        birthDate: profile.birthDate ?? new Date(),
        reasonSameDate: profile.reasonSameDate,
        telephoneNumber: profile.phone,
        nationality: profile.nationality,
        gender: profile.gender ?? "",
        relationship: profile.relationship ?? "",
        religion: profile.religion ?? "",
        bloodGroup: profile.bloodGroup ?? "",
        registrationAddress: profile.registrationAddress,
        registrationProvinceId: profile.registrationProvinceId,
        registrationDistrictId: profile.registrationDistrictId,
        registrationSubDistrictId: profile.registrationSubDistrictId,
        registrationZipCode: profile.registrationZipCode,
        currentAddress: profile.currentAddress,
        currentProvinceId: profile.currentProvinceId,
        currentSubDistrictId: profile.currentSubDistrictId,
        currentZipCode: profile.currentZipCode,
        dutyTimeId: profile.dutyTimeId,
        dutyTimeEffectiveDate: profile.dutyTimeEffectiveDate,
        posLevel: profile.posLevel?.posLevelName ?? "",
        posType: profile.posType?.posTypeName ?? "",
        // profileSalary: profile.profileSalary,
        profileSalary: profile.profileSalary?.map((x) => ({
          ...x,
          date: x.commandDateAffect ?? new Date()
        })) ?? [],
        // profileInsignia: profile.profileInsignias.map((x) => {
        //   return { ...x, insignia: x.insignia.name };
        // }),
         profileInsignia: profile.profileInsignias?.map((x) => ({
          ...x,
          insigniaId: x.insignia?.id ?? null,
          insignia: x.insignia?.name ?? null,
        })) ?? [],
        amount: profile.amount,
        positionSalaryAmount: profile.positionSalaryAmount,
        mouthSalaryAmount: profile.mouthSalaryAmount,
        profileType: "OFFICER",
        root:
          profile?.current_holders?.find(
            (x) =>
              x.orgRevision?.orgRevisionIsDraft == false &&
              x.orgRevision?.orgRevisionIsCurrent == true,
          )?.orgRoot?.orgRootName ?? null,
        rootId:
          profile?.current_holders?.find(
            (x) =>
              x.orgRevision?.orgRevisionIsDraft == false &&
              x.orgRevision?.orgRevisionIsCurrent == true,
          )?.orgRootId ?? null,
        rootDnaId:
          profile?.current_holders?.find(
            (x) =>
              x.orgRevision?.orgRevisionIsDraft == false &&
              x.orgRevision?.orgRevisionIsCurrent == true,
          )?.orgRoot?.ancestorDNA ?? null,
        child1:
          profile?.current_holders?.find(
            (x) =>
              x.orgRevision?.orgRevisionIsDraft == false &&
              x.orgRevision?.orgRevisionIsCurrent == true,
          )?.orgChild1?.orgChild1Name ?? null,
        child1Id:
          profile?.current_holders?.find(
            (x) =>
              x.orgRevision?.orgRevisionIsDraft == false &&
              x.orgRevision?.orgRevisionIsCurrent == true,
          )?.orgChild1Id ?? null,
        child1DnaId:
          profile?.current_holders?.find(
            (x) =>
              x.orgRevision?.orgRevisionIsDraft == false &&
              x.orgRevision?.orgRevisionIsCurrent == true,
          )?.orgChild1?.ancestorDNA ?? null,
        child2:
          profile?.current_holders?.find(
            (x) =>
              x.orgRevision?.orgRevisionIsDraft == false &&
              x.orgRevision?.orgRevisionIsCurrent == true,
          )?.orgChild2?.orgChild2Name ?? null,
        child2Id:
          profile?.current_holders?.find(
            (x) =>
              x.orgRevision?.orgRevisionIsDraft == false &&
              x.orgRevision?.orgRevisionIsCurrent == true,
          )?.orgChild2Id ?? null,
        child2DnaId:
          profile?.current_holders?.find(
            (x) =>
              x.orgRevision?.orgRevisionIsDraft == false &&
              x.orgRevision?.orgRevisionIsCurrent == true,
          )?.orgChild2?.ancestorDNA ?? null,
        child3:
          profile?.current_holders?.find(
            (x) =>
              x.orgRevision?.orgRevisionIsDraft == false &&
              x.orgRevision?.orgRevisionIsCurrent == true,
          )?.orgChild3?.orgChild3Name ?? null,
        child3Id:
          profile?.current_holders?.find(
            (x) =>
              x.orgRevision?.orgRevisionIsDraft == false &&
              x.orgRevision?.orgRevisionIsCurrent == true,
          )?.orgChild3Id ?? null,
        child3DnaId:
          profile?.current_holders?.find(
            (x) =>
              x.orgRevision?.orgRevisionIsDraft == false &&
              x.orgRevision?.orgRevisionIsCurrent == true,
          )?.orgChild3?.ancestorDNA ?? null,
        child4:
          profile?.current_holders?.find(
            (x) =>
              x.orgRevision?.orgRevisionIsDraft == false &&
              x.orgRevision?.orgRevisionIsCurrent == true,
          )?.orgChild4?.orgChild4Name ?? null,
        child4Id:
          profile?.current_holders?.find(
            (x) =>
              x.orgRevision?.orgRevisionIsDraft == false &&
              x.orgRevision?.orgRevisionIsCurrent == true,
          )?.orgChild4Id ?? null,
        child4DnaId:
          profile?.current_holders?.find(
            (x) =>
              x.orgRevision?.orgRevisionIsDraft == false &&
              x.orgRevision?.orgRevisionIsCurrent == true,
          )?.orgChild4?.ancestorDNA ?? null,
        posNo: shortName ?? "",
        markDiscipline: profile.profileDisciplines.length > 0 ? true : false,
        markLeave: false,
        markRate: profile.profileAssessments.length > 0 ? true : false,
        markInsignia: profile.profileInsignias.length > 0 ? true : false,
        apr1: aprAverages[currentYear]
          ? Extension.textPoint(aprAverages[currentYear] as number)
          : null,
        apr2: aprAverages[currentYear - 1]
          ? Extension.textPoint(aprAverages[currentYear - 1] as number)
          : null,
        apr3: aprAverages[currentYear - 2]
          ? Extension.textPoint(aprAverages[currentYear - 2] as number)
          : null,
        apr4: aprAverages[currentYear - 3]
          ? Extension.textPoint(aprAverages[currentYear - 3] as number)
          : null,
        apr5: aprAverages[currentYear - 4]
          ? Extension.textPoint(aprAverages[currentYear - 4] as number)
          : null,
        oct1: octAverages[currentYear]
          ? Extension.textPoint(octAverages[currentYear] as number)
          : null,
        oct2: octAverages[currentYear - 1]
          ? Extension.textPoint(octAverages[currentYear - 1] as number)
          : null,
        oct3: octAverages[currentYear - 2]
          ? Extension.textPoint(octAverages[currentYear - 2] as number)
          : null,
        oct4: octAverages[currentYear - 3]
          ? Extension.textPoint(octAverages[currentYear - 3] as number)
          : null,
        oct5: octAverages[currentYear - 4]
          ? Extension.textPoint(octAverages[currentYear - 4] as number)
          : null,
      };
    });

    return new HttpSuccess(mapProfile);
  }

  /**
   * 3.	API Get Profile จาก keycloak id
   *
   * @summary 3. API Get Profile จาก keycloak id
   *
   * @param {string} keycloakId  Id keycloak
   */
  @Get("root/employee/{rootId}")
  async GetProfileByRootIdEmpAsync(@Path() rootId: string) {
    const profiles = await this.profileEmpRepo.find({
      relations: {
        posLevel: true,
        posType: true,
        profileSalary: true,
        profileInsignias: true,
      },
      where: { current_holders: { orgRootId: rootId } },
      order: {
        profileSalary: {
          commandDateAffect: "DESC",
        },
        profileInsignias: {
          receiveDate: "DESC",
        },
      },
    });
    // if (!profile) throw new HttpError(HttpStatus.NOT_FOUND, "ไม่พบข้อมูล");

    const mapProfile = profiles.map((profile) => ({
      id: profile.id,
      avatar: profile.avatar,
      avatarName: profile.avatarName,
      rank: profile.rank,
      prefix: profile.prefix,
      firstName: profile.firstName,
      lastName: profile.lastName,
      citizenId: profile.citizenId,
      position: profile.position,
      posLevelId: profile.posLevelId,
      email: profile.email,
      phone: profile.phone,
      keycloak: profile.keycloak,
      isProbation: profile.isProbation,
      isLeave: profile.isLeave,
      leaveReason: profile.leaveReason,
      dateRetire: profile.dateRetire,
      dateAppoint: profile.dateAppoint,
      dateRetireLaw: profile.dateRetireLaw,
      dateStart: profile.dateStart,
      govAgeAbsent: profile.govAgeAbsent,
      govAgePlus: profile.govAgePlus,
      birthDate: profile.birthDate,
      reasonSameDate: profile.reasonSameDate,
      telephoneNumber: profile.phone,
      nationality: profile.nationality,
      gender: profile.gender,
      relationship: profile.relationship,
      religion: profile.religion,
      bloodGroup: profile.bloodGroup,
      registrationAddress: profile.registrationAddress,
      registrationProvinceId: profile.registrationProvinceId,
      registrationDistrictId: profile.registrationDistrictId,
      registrationSubDistrictId: profile.registrationSubDistrictId,
      registrationZipCode: profile.registrationZipCode,
      currentAddress: profile.currentAddress,
      currentProvinceId: profile.currentProvinceId,
      currentSubDistrictId: profile.currentSubDistrictId,
      currentZipCode: profile.currentZipCode,
      //   dutyTimeId: profile.dutyTimeId,
      //   dutyTimeEffectiveDate: profile.dutyTimeEffectiveDate,
      posLevel: profile.posLevel ? profile.posLevel : null,
      posType: profile.posType ? profile.posType : null,
      profileSalary: profile.profileSalary,
      // profileInsignia: profile.profileInsignias,
      profileInsignia: profile.profileInsignias?.map((x) => ({
          ...x,
          insigniaId: x.insignia?.id ?? null,
          insignia: x.insignia?.name ?? null,
        })) ?? [],
    }));

    return new HttpSuccess(mapProfile);
  }

  @Post("find/employee/position")
  async GetProfileByPositionEmpAsync(
    @Body()
    body: {
      empPosId: string[];
      rootId: string;
    },
  ) {
    const findRevision = await this.orgRevisionRepository.findOne({
      where: { orgRevisionIsCurrent: true },
    });
    const employeePosDict = await this.employeePosDictRepository.find({
      where: { id: In(body.empPosId) },
    });

    const profiles = await this.profileEmpRepo.find({
      relations: [
        "posLevel",
        "posType",
        "profileSalary",
        "profileInsignias",
        "profileInsignias.insignia",
        "profileDisciplines",
        "profileAssessments",
        "current_holders",
        "current_holders.orgRevision",
        "current_holders.orgRoot",
        "current_holders.orgChild1",
        "current_holders.orgChild2",
        "current_holders.orgChild3",
        "current_holders.orgChild4",
      ],
      where: employeePosDict.map((entry) => ({
        posLevelId: entry.posLevelId,
        posTypeId: entry.posTypeId,
        position: entry.posDictName,
        current_holders: { orgRootId: body.rootId },
      })),
      order: {
        profileSalary: {
          commandDateAffect: "DESC",
        },
        profileInsignias: {
          receiveDate: "DESC",
        },
      },
    });

    const currentYear = new Date().getFullYear();
    const years = [currentYear, currentYear - 1, currentYear - 2, currentYear - 3, currentYear - 4];

    // APR Averages
    const aprAverages: { [year: number]: number | null } = {};
    const aprSums: { [year: number]: number } = {};
    const aprCounts: { [year: number]: number } = {};

    // OCT Averages
    const octAverages: { [year: number]: number | null } = {};
    const octSums: { [year: number]: number } = {};
    const octCounts: { [year: number]: number } = {};

    years.forEach((year) => {
      aprAverages[year] = null;
      aprSums[year] = 0;
      aprCounts[year] = 0;

      octAverages[year] = null;
      octSums[year] = 0;
      octCounts[year] = 0;
    });

    profiles.forEach((profile) => {
      const assessments = profile.profileAssessments || [];

      assessments.forEach((assessment) => {
        const year = Number(assessment.year);

        if (years.includes(year)) {
          if (assessment.period === "APR") {
            aprSums[year] += assessment.pointSum;
            aprCounts[year] += 1;
          }

          if (assessment.period === "OCT") {
            octSums[year] += assessment.pointSum;
            octCounts[year] += 1;
          }
        }
      });
    });

    years.forEach((year) => {
      aprAverages[year] = aprCounts[year] > 0 ? aprSums[year] / aprCounts[year] : null;
      octAverages[year] = octCounts[year] > 0 ? octSums[year] / octCounts[year] : null;
    });

    const mapProfile = profiles.map((profile) => {
      const shortName =
        profile.current_holders.length == 0
          ? null
          : profile.current_holders.find((x) => x.orgRevisionId == findRevision?.id) != null &&
              profile.current_holders.find((x) => x.orgRevisionId == findRevision?.id)?.orgChild4 !=
                null
            ? `${profile.current_holders.find((x) => x.orgRevisionId == findRevision?.id)?.orgChild4.orgChild4ShortName} ${profile.current_holders.find((x) => x.orgRevisionId == findRevision?.id)?.posMasterNo}`
            : profile.current_holders.find((x) => x.orgRevisionId == findRevision?.id) != null &&
                profile.current_holders.find((x) => x.orgRevisionId == findRevision?.id)
                  ?.orgChild3 != null
              ? `${profile.current_holders.find((x) => x.orgRevisionId == findRevision?.id)?.orgChild3.orgChild3ShortName} ${profile.current_holders.find((x) => x.orgRevisionId == findRevision?.id)?.posMasterNo}`
              : profile.current_holders.find((x) => x.orgRevisionId == findRevision?.id) != null &&
                  profile.current_holders.find((x) => x.orgRevisionId == findRevision?.id)
                    ?.orgChild2 != null
                ? `${profile.current_holders.find((x) => x.orgRevisionId == findRevision?.id)?.orgChild2.orgChild2ShortName} ${profile.current_holders.find((x) => x.orgRevisionId == findRevision?.id)?.posMasterNo}`
                : profile.current_holders.find((x) => x.orgRevisionId == findRevision?.id) !=
                      null &&
                    profile.current_holders.find((x) => x.orgRevisionId == findRevision?.id)
                      ?.orgChild1 != null
                  ? `${profile.current_holders.find((x) => x.orgRevisionId == findRevision?.id)?.orgChild1.orgChild1ShortName} ${profile.current_holders.find((x) => x.orgRevisionId == findRevision?.id)?.posMasterNo}`
                  : profile.current_holders.find((x) => x.orgRevisionId == findRevision?.id) !=
                        null &&
                      profile.current_holders.find((x) => x.orgRevisionId == findRevision?.id)
                        ?.orgRoot != null
                    ? `${profile.current_holders.find((x) => x.orgRevisionId == findRevision?.id)?.orgRoot.orgRootShortName} ${profile.current_holders.find((x) => x.orgRevisionId == findRevision?.id)?.posMasterNo}`
                    : null;
      return {
        id: profile.id,
        avatar: profile.avatar,
        avatarName: profile.avatarName,
        rank: profile.rank ?? "",
        prefix: profile.prefix ?? "",
        firstName: profile.firstName ?? "",
        lastName: profile.lastName ?? "",
        citizenId: profile.citizenId ?? "",
        position: profile.position ?? "",
        posLevelId: profile.posLevelId,
        email: profile.email,
        phone: profile.phone,
        keycloak: profile.keycloak,
        isProbation: profile.isProbation,
        isLeave: profile.isLeave,
        leaveReason: profile.leaveReason,
        dateRetire: profile.dateRetire,
        dateAppoint: profile.dateAppoint,
        dateRetireLaw: profile.dateRetireLaw,
        dateStart: profile.dateStart,
        govAgeAbsent: profile.govAgeAbsent,
        govAgePlus: profile.govAgePlus,
        birthDate: profile.birthDate ?? new Date(),
        reasonSameDate: profile.reasonSameDate,
        telephoneNumber: profile.phone,
        nationality: profile.nationality,
        gender: profile.gender ?? "",
        relationship: profile.relationship ?? "",
        religion: profile.religion ?? "",
        bloodGroup: profile.bloodGroup ?? "",
        registrationAddress: profile.registrationAddress,
        registrationProvinceId: profile.registrationProvinceId,
        registrationDistrictId: profile.registrationDistrictId,
        registrationSubDistrictId: profile.registrationSubDistrictId,
        registrationZipCode: profile.registrationZipCode,
        currentAddress: profile.currentAddress,
        currentProvinceId: profile.currentProvinceId,
        currentSubDistrictId: profile.currentSubDistrictId,
        currentZipCode: profile.currentZipCode,
        posLevel:
          (profile.posType == null || profile.posType?.posTypeShortName == null
            ? ""
            : profile.posType?.posTypeShortName + " ") + (profile.posLevel?.posLevelName ?? ""),
        posType: profile.posType?.posTypeName ?? "",
        // profileSalary: profile.profileSalary.map((x) => {
        //   return { ...x, date: x.commandDateAffect ?? new Date() };
        // }),
        profileSalary: profile.profileSalary?.map((x) => ({
          ...x,
          date: x.commandDateAffect ?? new Date()
        })) ?? [],
        // profileInsignia: profile.profileInsignias.map((x) => {
        //   return { ...x, insignia: x.insignia.name };
        // }),
        profileInsignia: profile.profileInsignias?.map((x) => ({
          ...x,
          insigniaId: x.insignia?.id ?? null,
          insignia: x.insignia?.name ?? null,
        })) ?? [],
        amount: profile.amount,
        positionSalaryAmount: profile.positionSalaryAmount,
        mouthSalaryAmount: profile.mouthSalaryAmount,
        profileType: "EMPLOYEE",
        root:
          profile?.current_holders?.find(
            (x) =>
              x.orgRevision?.orgRevisionIsDraft == false &&
              x.orgRevision?.orgRevisionIsCurrent == true,
          )?.orgRoot?.orgRootName ?? null,
        rootId:
          profile?.current_holders?.find(
            (x) =>
              x.orgRevision?.orgRevisionIsDraft == false &&
              x.orgRevision?.orgRevisionIsCurrent == true,
          )?.orgRootId ?? null,
        rootDnaId:
          profile?.current_holders?.find(
            (x) =>
              x.orgRevision?.orgRevisionIsDraft == false &&
              x.orgRevision?.orgRevisionIsCurrent == true,
          )?.orgRoot?.ancestorDNA ?? null,
        child1:
          profile?.current_holders?.find(
            (x) =>
              x.orgRevision?.orgRevisionIsDraft == false &&
              x.orgRevision?.orgRevisionIsCurrent == true,
          )?.orgChild1?.orgChild1Name ?? null,
        child1Id:
          profile?.current_holders?.find(
            (x) =>
              x.orgRevision?.orgRevisionIsDraft == false &&
              x.orgRevision?.orgRevisionIsCurrent == true,
          )?.orgChild1Id ?? null,
        child1DnaId:
          profile?.current_holders?.find(
            (x) =>
              x.orgRevision?.orgRevisionIsDraft == false &&
              x.orgRevision?.orgRevisionIsCurrent == true,
          )?.orgChild1?.ancestorDNA ?? null,
        child2:
          profile?.current_holders?.find(
            (x) =>
              x.orgRevision?.orgRevisionIsDraft == false &&
              x.orgRevision?.orgRevisionIsCurrent == true,
          )?.orgChild2?.orgChild2Name ?? null,
        child2Id:
          profile?.current_holders?.find(
            (x) =>
              x.orgRevision?.orgRevisionIsDraft == false &&
              x.orgRevision?.orgRevisionIsCurrent == true,
          )?.orgChild2Id ?? null,
        child2DnaId:
          profile?.current_holders?.find(
            (x) =>
              x.orgRevision?.orgRevisionIsDraft == false &&
              x.orgRevision?.orgRevisionIsCurrent == true,
          )?.orgChild2?.ancestorDNA ?? null,
        child3:
          profile?.current_holders?.find(
            (x) =>
              x.orgRevision?.orgRevisionIsDraft == false &&
              x.orgRevision?.orgRevisionIsCurrent == true,
          )?.orgChild3?.orgChild3Name ?? null,
        child3Id:
          profile?.current_holders?.find(
            (x) =>
              x.orgRevision?.orgRevisionIsDraft == false &&
              x.orgRevision?.orgRevisionIsCurrent == true,
          )?.orgChild3Id ?? null,
        child3DnaId:
          profile?.current_holders?.find(
            (x) =>
              x.orgRevision?.orgRevisionIsDraft == false &&
              x.orgRevision?.orgRevisionIsCurrent == true,
          )?.orgChild3?.ancestorDNA ?? null,
        child4:
          profile?.current_holders?.find(
            (x) =>
              x.orgRevision?.orgRevisionIsDraft == false &&
              x.orgRevision?.orgRevisionIsCurrent == true,
          )?.orgChild4?.orgChild4Name ?? null,
        child4Id:
          profile?.current_holders?.find(
            (x) =>
              x.orgRevision?.orgRevisionIsDraft == false &&
              x.orgRevision?.orgRevisionIsCurrent == true,
          )?.orgChild4Id ?? null,
        child4DnaId:
          profile?.current_holders?.find(
            (x) =>
              x.orgRevision?.orgRevisionIsDraft == false &&
              x.orgRevision?.orgRevisionIsCurrent == true,
          )?.orgChild4?.ancestorDNA ?? null,
        posNo: shortName ?? "",
        markDiscipline: profile.profileDisciplines.length > 0 ? true : false,
        markLeave: false,
        markRate: profile.profileAssessments.length > 0 ? true : false,
        markInsignia: profile.profileInsignias.length > 0 ? true : false,
        apr1: aprAverages[currentYear]
          ? Extension.textPoint(aprAverages[currentYear] as number)
          : null,
        apr2: aprAverages[currentYear - 1]
          ? Extension.textPoint(aprAverages[currentYear - 1] as number)
          : null,
        apr3: aprAverages[currentYear - 2]
          ? Extension.textPoint(aprAverages[currentYear - 2] as number)
          : null,
        apr4: aprAverages[currentYear - 3]
          ? Extension.textPoint(aprAverages[currentYear - 3] as number)
          : null,
        apr5: aprAverages[currentYear - 4]
          ? Extension.textPoint(aprAverages[currentYear - 4] as number)
          : null,
        oct1: octAverages[currentYear]
          ? Extension.textPoint(octAverages[currentYear] as number)
          : null,
        oct2: octAverages[currentYear - 1]
          ? Extension.textPoint(octAverages[currentYear - 1] as number)
          : null,
        oct3: octAverages[currentYear - 2]
          ? Extension.textPoint(octAverages[currentYear - 2] as number)
          : null,
        oct4: octAverages[currentYear - 3]
          ? Extension.textPoint(octAverages[currentYear - 3] as number)
          : null,
        oct5: octAverages[currentYear - 4]
          ? Extension.textPoint(octAverages[currentYear - 4] as number)
          : null,
      };
    });

    return new HttpSuccess(mapProfile);
  }

  /**
   * API ยืนยัน Email
   *
   * @summary ยืนยัน Email
   *
   */
  @Post("verify-email")
  async genLinkVerifyEmail(@Body() body: { token: string }) {
    const jwt = require("jsonwebtoken");
    const secretKey = process.env.AUTH_ACCOUNT_SECRET || "defaultSecretKey";
    const decodedToken = jwt.verify(body.token, secretKey);
    // console.log("[email]",decodedToken);
    // console.log("[1]",decodedToken.email_id);

    const profile = await this.profileRepo.findOne({
      where: {
        id: decodedToken.profileId,
        email: decodedToken.email_id,
      },
    });
    if (!profile) {
      throw new HttpError(HttpStatus.NOT_FOUND, "ไม่พบข้อมูลโปรไฟล์");
    }

    Object.assign(profile, body);
    profile.statusEmail = "VERIFIED";
    await this.profileRepo.save(profile);
    return new HttpSuccess("Email verified successfully.");
  }

  /**
   * API ผลการประเมิน 5 ปีย้อนหลังนับจากปีปัจจุบัน
   *
   * @summary ผลการประเมิน 5 ปีย้อนหลังนับจากปีปัจจุบัน
   *
   */
  @Get("calculateEvaluation/{type}")
  async calculateEvaluation(
    @Path() type: string,
    // @Path() nodeId: string,
  ) {
    const conType = type.toUpperCase();
    // let condition :any = {};
    // switch (node) {
    //   case 0:
    //     condition = {orgRootId: nodeId}
    //     break;
    //   case 1:
    //     condition = {orgChild1Id: nodeId}
    //     break;
    //   case 2:
    //     condition = {orgChild2Id: nodeId}
    //     break;
    //   case 3:
    //     condition = {orgChild3Id: nodeId}
    //     break;
    //   case 4:
    //     condition = {orgChild4Id: nodeId}
    //     break;
    //   default:
    //     throw new HttpError(HttpStatus.NOT_FOUND, "ไม่พบข้อมูล");
    // }
    let lists = null;
    lists = await this.viewProfileEvaluationRepo.find({
      // where:{
      //   ...condition
      // }
    });
    if (conType == "EMPLOYEE") {
      lists = await this.viewProfileEmployeeEvaluationRepo.find({});
    }
    const groupData: any = {};
    const year = new Date().getFullYear();
    const years = [year, year - 1, year - 2, year - 3, year - 4];

    lists.forEach((item: any) => {
      if (!groupData[conType == "EMPLOYEE" ? item.profileEmployeeId : item.profileId]) {
        groupData[conType == "EMPLOYEE" ? item.profileEmployeeId : item.profileId] = {
          profileId: conType == "EMPLOYEE" ? item.profileEmployeeId : item.profileId,
          yearAPR1: "-",
          periodAPR1: "-",
          resultAPR1: "-",
          yearOCT1: "-",
          periodOCT1: "-",
          resultOCT1: "-",
          yearAPR2: "-",
          periodAPR2: "-",
          resultAPR2: "-",
          yearOCT2: "-",
          periodOCT2: "-",
          resultOCT2: "-",
          yearAPR3: "-",
          periodAPR3: "-",
          resultAPR3: "-",
          yearOCT3: "-",
          periodOCT3: "-",
          resultOCT3: "-",
          yearAPR4: "-",
          periodAPR4: "-",
          resultAPR4: "-",
          yearOCT4: "-",
          periodOCT4: "-",
          resultOCT4: "-",
          yearAPR5: "-",
          periodAPR5: "-",
          resultAPR5: "-",
          yearOCT5: "-",
          periodOCT5: "-",
          resultOCT5: "-",
        };
      }
      const yearIndex = years.indexOf(parseInt(item.year));
      if (yearIndex !== -1) {
        const yearSuffix = yearIndex + 1;
        const yearKey = `year${item.period}${yearSuffix}`;
        const periodKey = `period${item.period}${yearSuffix}`;
        const resultKey = `result${item.period}${yearSuffix}`;

        groupData[conType == "EMPLOYEE" ? item.profileEmployeeId : item.profileId][yearKey] =
          item.year;
        groupData[conType == "EMPLOYEE" ? item.profileEmployeeId : item.profileId][periodKey] =
          item.period;
        groupData[conType == "EMPLOYEE" ? item.profileEmployeeId : item.profileId][resultKey] =
          item.result;
      }
    });
    const formattedResults = Object.values(groupData).map((x: any) => ({
      profileId: x.profileId,
      yearAPR1: x.yearAPR1,
      periodAPR1: x.periodAPR1,
      resultAPR1: x.resultAPR1 ? Extension.textPoint(x.resultAPR1) : "-",
      yearOCT1: x.yearOCT1,
      periodOCT1: x.periodOCT1,
      resultOCT1: x.resultOCT1 ? Extension.textPoint(x.resultOCT1) : "-",
      yearAPR2: x.yearAPR2,
      periodAPR2: x.periodAPR2,
      resultAPR2: x.resultAPR2 ? Extension.textPoint(x.resultAPR2) : "-",
      yearOCT2: x.yearOCT2,
      periodOCT2: x.periodOCT2,
      resultOCT2: x.resultOCT2 ? Extension.textPoint(x.resultOCT2) : "-",
      yearAPR3: x.yearAPR3,
      periodAPR3: x.periodAPR3,
      resultAPR3: x.resultAPR3 ? Extension.textPoint(x.resultAPR3) : "-",
      yearOCT3: x.yearOCT3,
      periodOCT3: x.periodOCT3,
      resultOCT3: x.resultOCT3 ? Extension.textPoint(x.resultOCT3) : "-",
      yearAPR4: x.yearAPR4,
      periodAPR4: x.periodAPR4,
      resultAPR4: x.resultAPR4 ? Extension.textPoint(x.resultAPR4) : "-",
      yearOCT4: x.yearOCT4,
      periodOCT4: x.periodOCT4,
      resultOCT4: x.resultOCT4 ? Extension.textPoint(x.resultOCT4) : "-",
      yearAPR5: x.yearAPR5,
      periodAPR5: x.periodAPR5,
      resultAPR5: x.resultAPR5 ? Extension.textPoint(x.resultAPR5) : "-",
      yearOCT5: x.yearOCT5,
      periodOCT5: x.periodOCT5,
      resultOCT5: x.resultOCT5 ? Extension.textPoint(x.resultOCT5) : "-",
    }));

    return new HttpSuccess(formattedResults);
  }

  @Patch("retirement")
  public async updateStatusRetirement(
    @Body()
    body: {
      data: {
        profileId: string;
      }[];
    },
  ) {
    let profiles: Profile[] = [];
    let _null: any = null;
    await Promise.all(
      body.data.map(async (item) => {
        const _profile = await this.profileRepo.findOneBy({ id: item.profileId });
        if (!_profile) throw new HttpError(HttpStatus.NOT_FOUND, "ไม่พบข้อมูล");
        _profile.isRetirement = true;
        _profile.isLeave = true;
        _profile.leaveType = "RETIRE";
        _profile.leaveDate = new Date();
        _profile.dateLeave = new Date();
        _profile.lastUpdatedAt = new Date();
        profiles.push(_profile);
      }),
    );
    await this.profileRepo.save(profiles);
    return new HttpSuccess();
  }

  @Patch("retirement-employee")
  public async updateStatusRetirementEmp(
    @Body()
    body: {
      data: {
        profileId: string;
      }[];
    },
  ) {
    let profiles: ProfileEmployee[] = [];
    let _null: any = null;
    await Promise.all(
      body.data.map(async (item) => {
        const _profile = await this.profileEmpRepo.findOneBy({ id: item.profileId });
        if (!_profile) throw new HttpError(HttpStatus.NOT_FOUND, "ไม่พบข้อมูล");
        _profile.isRetirement = true;
        _profile.isLeave = true;
        _profile.leaveType = "RETIRE";
        _profile.leaveDate = new Date();
        _profile.dateLeave = new Date();
        _profile.lastUpdatedAt = new Date();
        profiles.push(_profile);
      }),
    );
    await this.profileEmpRepo.save(profiles);
    return new HttpSuccess();
  }

  /**
   * API รายชื่อข้าราชการ (unauthorize)
   *
   * @summary รายชื่อข้าราชการ
   *
   */
  @Post("officer-list")
  async officerList(
    @Body()
    body: {
      reqNode?: number;
      reqNodeId?: string;
      date: Date;
    },
  ) {
    let typeCondition: any = {};

    // Build typeCondition based on reqNode and reqNodeId (similar to OWNER/ROOT/PARENT logic)
    switch (body.reqNode) {
      case 0:
        typeCondition = {
          rootDnaId: body.reqNodeId,
        };
        break;
      case 1:
        typeCondition = {
          child1DnaId: body.reqNodeId,
        };
        break;
      case 2:
        typeCondition = {
          child2DnaId: body.reqNodeId,
        };
        break;
      case 3:
        typeCondition = {
          child3DnaId: body.reqNodeId,
        };
        break;
      case 4:
        typeCondition = {
          child4DnaId: body.reqNodeId,
        };
        break;
      default:
        typeCondition = {};
        break;
    }

    const date = body.date ? new Date(body.date.toISOString().slice(0, 10)) : new Date();
    // set เวลาเป็น 23:59:59 ของวันนั้น
    date.setHours(23, 59, 59, 999);

    let profile = await this.posMasterHistoryRepository.find({
      where: {
        ...typeCondition,
        createdAt: LessThanOrEqual(date),
      },
      order: {
        firstName: "ASC",
        lastName: "ASC",
        createdAt: "DESC",
      },
    });

    // group1: group by ancestorDNA แล้วเลือก create_at ล่าสุด
    const grouped1 = new Map<string, PosMasterHistory>();
    for (const item of profile) {
      const key = `${item.ancestorDNA}`;
      if (!grouped1.has(key)) {
        grouped1.set(key, item);
      } else {
        const exist = grouped1.get(key);
        if (exist && item.createdAt > exist.createdAt) {
          grouped1.set(key, item);
        }
      }
    }
    // group2: group by shortName-posMasterNo จากค่าที่ได้จาก group1
    const grouped2 = new Map<string, PosMasterHistory>();
    for (const item of Array.from(grouped1.values())) {
      const key = `${item.shortName}-${item.posMasterNo}`;
      if (!grouped2.has(key)) {
        grouped2.set(key, item);
      } else {
        const exist = grouped2.get(key);
        if (exist && item.createdAt > exist.createdAt) {
          grouped2.set(key, item);
        }
      }
    }
    // group3: group by firstName-lastName จากค่าที่ได้จาก group2
    const grouped3 = new Map<string, PosMasterHistory>();
    for (const item of Array.from(grouped2.values())) {
      const key = `${item.firstName}-${item.lastName}`;
      if (!grouped3.has(key)) {
        grouped3.set(key, item);
      } else {
        const exist = grouped3.get(key);
        if (exist && item.createdAt > exist.createdAt) {
          grouped3.set(key, item);
        }
      }
    }

    const profile_ = await Promise.all(
      Array.from(grouped3.values())
        .filter((x) => x.profileId != null)
        .map(async (item: PosMasterHistory) => {
          let profile = await this.profileRepo.findOne({
            where: { id: item.profileId },
          });

          return {
            id: item.profileId,
            prefix: item.prefix,
            firstName: item.firstName,
            lastName: item.lastName,
            citizenId: profile?.citizenId ?? null,
            dateStart: profile?.dateStart ?? null,
            dateAppoint: profile?.dateAppoint ?? null,
            keycloak: profile?.keycloak ?? null,
            posNo: `${item.shortName} ${item.posMasterNo}`,
            position: item.position,
            positionLevel: item.posLevel,
            positionType: item.posType,
            orgRootId: item.rootDnaId,
            orgChild1Id: item.child1DnaId,
            orgChild2Id: item.child2DnaId,
            orgChild3Id: item.child3DnaId,
            orgChild4Id: item.child4DnaId,
          };
        }),
    );

    return new HttpSuccess(
      (profile_ ?? []).sort((a, b) => a.posNo.localeCompare(b.posNo, undefined, { numeric: true })),
    );
  }

  /**
   * API รายชื่อพนักงาน (unauthorize)
   *
   * @summary รายชื่อพนักงาน
   *
   */
  @Post("employee-list")
  async employeeList(
    @Body()
    body: {
      reqNode?: number;
      reqNodeId?: string;
      startDate?: Date;
      endDate?: Date;
      revisionId?: string;
    },
  ) {
    let typeCondition: any = {};

    // Build typeCondition based on reqNode and reqNodeId (similar to OWNER/ROOT/PARENT logic)
    switch (body.reqNode) {
      case 0:
        typeCondition = {
          orgRoot: {
            id: body.reqNodeId,
          },
        };
        break;
      case 1:
        typeCondition = {
          orgChild1: {
            id: body.reqNodeId,
          },
        };
        break;
      case 2:
        typeCondition = {
          orgChild2: {
            id: body.reqNodeId,
          },
        };
        break;
      case 3:
        typeCondition = {
          orgChild3: {
            id: body.reqNodeId,
          },
        };
        break;
      case 4:
        typeCondition = {
          orgChild4: {
            id: body.reqNodeId,
          },
        };
        break;
      default:
        typeCondition = {};
        break;
    }

    let profile = await this.profileEmpRepo.find({
      where: { isLeave: false, isRetirement: false, current_holders: typeCondition },
      relations: [
        "posType",
        "posLevel",
        "current_holders",
        "current_holders.orgRoot",
        "current_holders.orgChild1",
        "current_holders.orgChild2",
        "current_holders.orgChild3",
        "current_holders.orgChild4",
      ],
      order: {
        current_holders: {
          orgRoot: {
            orgRootOrder: "ASC",
          },
          orgChild1: {
            orgChild1Order: "ASC",
          },
          orgChild2: {
            orgChild2Order: "ASC",
          },
          orgChild3: {
            orgChild3Order: "ASC",
          },
          orgChild4: {
            orgChild4Order: "ASC",
          },
          posMasterNo: "ASC",
        },
      },
    });

    let findRevision = await this.orgRevisionRepository.findOne({
      where: { orgRevisionIsCurrent: true, orgRevisionIsDraft: false },
    });

    if (body.revisionId) {
      findRevision = await this.orgRevisionRepository.findOne({
        where: { id: body.revisionId },
      });
    }

    const profile_ = await Promise.all(
      profile.map(async (item: ProfileEmployee) => {
        const shortName =
          item.current_holders.length == 0
            ? null
            : item.current_holders.find((x) => x.orgRevisionId == findRevision?.id) != null &&
                item.current_holders.find((x) => x.orgRevisionId == findRevision?.id)?.orgChild4 !=
                  null
              ? `${item.current_holders.find((x) => x.orgRevisionId == findRevision?.id)?.orgChild4.orgChild4ShortName} ${item.current_holders.find((x) => x.orgRevisionId == findRevision?.id)?.posMasterNo}`
              : item.current_holders.find((x) => x.orgRevisionId == findRevision?.id) != null &&
                  item.current_holders.find((x) => x.orgRevisionId == findRevision?.id)
                    ?.orgChild3 != null
                ? `${item.current_holders.find((x) => x.orgRevisionId == findRevision?.id)?.orgChild3.orgChild3ShortName} ${item.current_holders.find((x) => x.orgRevisionId == findRevision?.id)?.posMasterNo}`
                : item.current_holders.find((x) => x.orgRevisionId == findRevision?.id) != null &&
                    item.current_holders.find((x) => x.orgRevisionId == findRevision?.id)
                      ?.orgChild2 != null
                  ? `${item.current_holders.find((x) => x.orgRevisionId == findRevision?.id)?.orgChild2.orgChild2ShortName} ${item.current_holders.find((x) => x.orgRevisionId == findRevision?.id)?.posMasterNo}`
                  : item.current_holders.find((x) => x.orgRevisionId == findRevision?.id) != null &&
                      item.current_holders.find((x) => x.orgRevisionId == findRevision?.id)
                        ?.orgChild1 != null
                    ? `${item.current_holders.find((x) => x.orgRevisionId == findRevision?.id)?.orgChild1.orgChild1ShortName} ${item.current_holders.find((x) => x.orgRevisionId == findRevision?.id)?.posMasterNo}`
                    : item.current_holders.find((x) => x.orgRevisionId == findRevision?.id) !=
                          null &&
                        item.current_holders.find((x) => x.orgRevisionId == findRevision?.id)
                          ?.orgRoot != null
                      ? `${item.current_holders.find((x) => x.orgRevisionId == findRevision?.id)?.orgRoot.orgRootShortName} ${item.current_holders.find((x) => x.orgRevisionId == findRevision?.id)?.posMasterNo}`
                      : null;
        const Oc =
          item.current_holders.length == 0
            ? null
            : item.current_holders[0].orgChild4 != null
              ? `${item.current_holders[0].orgChild4.orgChild4Name}/${item.current_holders[0].orgChild3.orgChild3Name}/${item.current_holders[0].orgChild2.orgChild2Name}/${item.current_holders[0].orgChild1.orgChild1Name}/${item.current_holders[0].orgRoot.orgRootName}`
              : item.current_holders[0].orgChild3 != null
                ? `${item.current_holders[0].orgChild3.orgChild3Name}/${item.current_holders[0].orgChild2.orgChild2Name}/${item.current_holders[0].orgChild1.orgChild1Name}/${item.current_holders[0].orgRoot.orgRootName}`
                : item.current_holders[0].orgChild2 != null
                  ? `${item.current_holders[0].orgChild2.orgChild2Name}/${item.current_holders[0].orgChild1.orgChild1Name}/${item.current_holders[0].orgRoot.orgRootName}`
                  : item.current_holders[0].orgChild1 != null
                    ? `${item.current_holders[0].orgChild1.orgChild1Name}/${item.current_holders[0].orgRoot.orgRootName}`
                    : item.current_holders[0].orgRoot != null
                      ? `${item.current_holders[0].orgRoot.orgRootName}`
                      : null;

        let _posMaster = await this.empPosMasterRepository.findOne({
          where: {
            orgRevisionId: findRevision?.id,
            current_holderId: item.id,
          },
        });

        return {
          id: item.id,
          prefix: item.prefix,
          firstName: item.firstName,
          lastName: item.lastName,
          citizenId: item.citizenId,
          dateStart: item.dateStart,
          dateAppoint: item.dateAppoint,
          keycloak: item.keycloak,
          posNo: shortName,
          position: item.position,
          positionLevel:
            item.posType?.posTypeShortName && item.posLevel?.posLevelName
              ? `${item.posType?.posTypeShortName} ${item.posLevel?.posLevelName}`
              : null,
          positionType: item.posType?.posTypeName ?? null,
          oc: Oc,
          orgRootId: _posMaster?.orgRootId,
          orgChild1Id: _posMaster?.orgChild1Id,
          orgChild2Id: _posMaster?.orgChild2Id,
          orgChild3Id: _posMaster?.orgChild3Id,
          orgChild4Id: _posMaster?.orgChild4Id,
        };
      }),
    );

    return new HttpSuccess(profile_);
  }

  /**
   * API สร้างข้อมูลการมาสาย/ขาดราชการของข้าราชการ (สำหรับ schedule)
   * @summary API สร้างข้อมูลการมาสาย/ขาดราชการของข้าราชการ (สำหรับ Job schedule)
   */
  @Post("profile/absent-late/batch")
  async newAbsentLateBatch(@Body() body: CreateProfileAbsentLateBatch) {
    // กรณีไม่มีข้อมูลส่งมา (วันที่ไม่มีคนขาด/มาสาย)
    if (!body.records || body.records.length === 0) {
      return new HttpSuccess({ count: 0, ids: [] });
    }

    const profileIds = [...new Set(body.records.map((r) => r.profileId))];
    const profiles = await this.profileRepo.findBy({
      id: In(profileIds),
    });

    const foundProfileIds = new Set(profiles.map((p) => p.id));
    const validRecords = body.records.filter((r) => foundProfileIds.has(r.profileId));

    // กรณีไม่พบ profile เลย
    if (validRecords.length === 0) {
      return new HttpSuccess({ count: 0, ids: [] });
    }

    const meta = {
      createdUserId: "SYSTEM",
      createdFullName: "SYSTEM",
      lastUpdateUserId: "SYSTEM",
      lastUpdateFullName: "SYSTEM",
      createdAt: new Date(),
      lastUpdatedAt: new Date(),
    };

    const records = validRecords.map((item) => {
      const data = new ProfileAbsentLate();
      Object.assign(data, { ...item, ...meta });
      return data;
    });

    const result = await this.absentLateRepo.save(records);

    // บันทึก history สำหรับแต่ละ record
    const historyRecords = result.map((data) => {
      const history = new ProfileAbsentLateHistory();
      Object.assign(history, { ...data, id: undefined });
      history.profileAbsentLateId = data.id;
      return history;
    });
    await this.absentLateHistoryRepo.save(historyRecords);

    return new HttpSuccess({ count: result.length, ids: result.map((r) => r.id) });
  }

  /**
   * API สร้างข้อมูลการมาสาย/ขาดราชการของลูกจ้างประจำ (สำหรับ schedule)
   * @summary API สร้างข้อมูลการมาสาย/ขาดราชการของลูกจ้างประจำ (สำหรับ schedule)
   */
  @Post("profile-employee/absent-late/batch")
  async newEmpAbsentLateBatch(@Body() body: CreateProfileEmployeeAbsentLateBatch) {
    // กรณีไม่มีข้อมูลส่งมา (วันที่ไม่มีคนขาด/มาสาย)
    if (!body.records || body.records.length === 0) {
      return new HttpSuccess({ count: 0, ids: [] });
    }

    const profileIds = [...new Set(body.records.map((r) => r.profileEmployeeId))];
    const profiles = await this.profileEmpRepo.findBy({
      id: In(profileIds),
    });

    const foundProfileIds = new Set(profiles.map((p) => p.id));
    const validRecords = body.records.filter((r) => foundProfileIds.has(r.profileEmployeeId));

    // กรณีไม่พบ profile เลย
    if (validRecords.length === 0) {
      return new HttpSuccess({ count: 0, ids: [] });
    }

    const meta = {
      createdUserId: "SYSTEM",
      createdFullName: "SYSTEM",
      lastUpdateUserId: "SYSTEM",
      lastUpdateFullName: "SYSTEM",
      createdAt: new Date(),
      lastUpdatedAt: new Date(),
    };

    const records = validRecords.map((item) => {
      const data = new ProfileEmployeeAbsentLate();
      Object.assign(data, { ...item, ...meta });
      return data;
    });

    const result = await this.empAbsentLateRepo.save(records);

    // บันทึก history สำหรับแต่ละ record
    const historyRecords = result.map((data) => {
      const history = new ProfileEmployeeAbsentLateHistory();
      Object.assign(history, { ...data, id: undefined });
      history.profileEmployeeAbsentLateId = data.id;
      return history;
    });
    await this.empAbsentLateHistoryRepo.save(historyRecords);

    return new HttpSuccess({ count: result.length, ids: result.map((r) => r.id) });
  }
}
