import {
  Body,
  Controller,
  Get,
  Patch,
  Path,
  Post,
  Put,
  Query,
  Request,
  Route,
  Security,
  Tags,
} from "tsoa";
import { AppDataSource } from "../database/data-source";
import { ProfileSalary } from "../entities/ProfileSalary";
import HttpSuccess from "../interfaces/http-success";
import HttpStatus from "../interfaces/http-status";
import HttpError from "../interfaces/http-error";
import HttpStatusCode from "../interfaces/http-status";
import { RequestWithUser } from "../middlewares/user";
import { Brackets, IsNull, LessThan, MoreThan, Not } from "typeorm";
import { setLogDataDiff } from "../interfaces/utils";
import {
  CreateProfileSalaryTemp,
  ProfileSalaryTemp,
  UpdateProfileSalaryTemp,
} from "../entities/ProfileSalaryTemp";
import { Profile } from "../entities/Profile";
import { ProfileEmployee } from "../entities/ProfileEmployee";
import permission from "../interfaces/permission";
import { OrgRevision } from "../entities/OrgRevision";
import Extension from "../interfaces/extension";
import {
  CreatePositionSalaryEditHistory,
  PositionSalaryEditHistory,
} from "../entities/PositionSalaryEditHistory";
import { ProfileSalaryBackup } from "../entities/ProfileSalaryBackup";
import { ProfileActposition } from "../entities/ProfileActposition";
import { ProfileAssistance } from "../entities/ProfileAssistance";

const SALARY_COMMAND_CODES = {
  ACT_POSITION: "17", // รักษาการ
  ASSISTANCE: "18", // ช่วยราชการ
} as const;

class ConfirmDoneSalaryDto {
  profileId: string;
  type: "OFFICER" | "EMPLOYEE";
}

@Route("api/v1/org/profile/salaryTemp")
@Tags("ProfileSalaryTemp")
@Security("bearerAuth")
export class ProfileSalaryTempController extends Controller {
  private profileRepo = AppDataSource.getRepository(Profile);
  private profileEmployeeRepo = AppDataSource.getRepository(ProfileEmployee);
  private salaryRepo = AppDataSource.getRepository(ProfileSalaryTemp);
  private salaryOldRepo = AppDataSource.getRepository(ProfileSalary);
  private orgRevisionRepo = AppDataSource.getRepository(OrgRevision);
  private positionSalaryEditHistoryRepo = AppDataSource.getRepository(PositionSalaryEditHistory);

  /**
   * API ค้นหารายการคน
   *
   * @summary API ค้นหารายการคน
   *
   */
  @Get()
  async listProfile(
    @Request() request: RequestWithUser,
    @Query("page") page: number = 1,
    @Query("pageSize") pageSize: number = 10,
    @Query()
    searchField?: "firstName" | "lastName" | "fullName" | "citizenId",
    @Query() type: string = "OFFICER",
    @Query() searchKeyword: string = "",
    @Query() statusCheckEdit?: string | null,
    @Query() rootId?: string,
    @Query("sortBy") sortBy?: string,
    @Query("descending") descending?: boolean,
  ) {
    if (type.trim().toUpperCase() == "OFFICER") {
      let _data = await new permission().PermissionOrgList(request, "SYS_REGISTRY_OFFICER");
      let queryLike =
        "CONCAT(profile.prefix, profile.firstName, ' ', profile.lastName) LIKE :keyword";
      if (searchField == "citizenId") {
        queryLike = "profile.citizenId LIKE :keyword";
      }
      const findRevision = await this.orgRevisionRepo.findOne({
        where: { orgRevisionIsCurrent: true },
      });
      if (!findRevision) {
        throw new HttpError(HttpStatus.NOT_FOUND, "not found. OrgRevision");
      }
      let query = await this.profileRepo
        .createQueryBuilder("profile")
        .leftJoinAndSelect("profile.posLevel", "posLevel")
        .leftJoinAndSelect("profile.posType", "posType")
        .leftJoinAndSelect("profile.current_holders", "current_holders")
        .leftJoinAndSelect("current_holders.positions", "positions")
        .leftJoinAndSelect("positions.posExecutive", "posExecutive")
        .leftJoinAndSelect("current_holders.orgRevision", "orgRevision")
        .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")
        .where("current_holders.orgRevisionId = :orgRevisionId", {
          orgRevisionId: findRevision.id,
        })
        .andWhere(
          statusCheckEdit != undefined &&
            statusCheckEdit != null &&
            statusCheckEdit.toUpperCase() != "ALL"
            ? "profile.statusCheckEdit = :statusCheckEdit"
            : "1=1",
          {
            statusCheckEdit: statusCheckEdit?.trim()?.toUpperCase() ?? null,
          },
        )
        .andWhere(
          _data.root != undefined && _data.root != null
            ? _data.root[0] != null
              ? `current_holders.orgRootId IN (:...root)`
              : `current_holders.orgRootId is null`
            : "1=1",
          {
            root: _data.root,
          },
        )
        .andWhere(
          _data.child1 != undefined && _data.child1 != null
            ? _data.child1[0] != null
              ? `current_holders.orgChild1Id IN (:...child1)`
              : // : `current_holders.orgChild1Id is ${_data.privilege == "PARENT" ? "not null" : "null"}`
                `current_holders.orgChild1Id is null`
            : "1=1",
          {
            child1: _data.child1,
          },
        )
        .andWhere(
          _data.child2 != undefined && _data.child2 != null
            ? _data.child2[0] != null
              ? `current_holders.orgChild2Id IN (:...child2)`
              : `current_holders.orgChild2Id is null`
            : "1=1",
          {
            child2: _data.child2,
          },
        )
        .andWhere(
          _data.child3 != undefined && _data.child3 != null
            ? _data.child3[0] != null
              ? `current_holders.orgChild3Id IN (:...child3)`
              : `current_holders.orgChild3Id is null`
            : "1=1",
          {
            child3: _data.child3,
          },
        )
        .andWhere(
          _data.child4 != undefined && _data.child4 != null
            ? _data.child4[0] != null
              ? `current_holders.orgChild4Id IN (:...child4)`
              : `current_holders.orgChild4Id is null`
            : "1=1",
          {
            child4: _data.child4,
          },
        )
        .andWhere(
          new Brackets((qb) => {
            qb.orWhere(
              searchKeyword != null && searchKeyword != ""
                ? `profile.citizenId like '%${searchKeyword}%'`
                : "1=1",
            )
              .orWhere(
                searchKeyword != null && searchKeyword != ""
                  ? `profile.position like '%${searchKeyword}%'`
                  : "1=1",
              )
              .orWhere(
                searchKeyword != null && searchKeyword != ""
                  ? `CONCAT(profile.prefix, profile.firstName," ",profile.lastName)  like '%${searchKeyword}%'`
                  : "1=1",
              )
              .orWhere(
                searchKeyword != null && searchKeyword != ""
                  ? `posType.posTypeName like '%${searchKeyword}%'`
                  : "1=1",
              )
              .orWhere(
                searchKeyword != null && searchKeyword != ""
                  ? `posLevel.posLevelName  like '%${searchKeyword}%'`
                  : "1=1",
              )
              .orWhere(
                searchKeyword != null && searchKeyword != ""
                  ? `orgRoot.orgRootName  like '%${searchKeyword}%'`
                  : "1=1",
              )
              .orWhere(
                searchKeyword != null && searchKeyword != ""
                  ? `orgChild1.orgChild1Name  like '%${searchKeyword}%'`
                  : "1=1",
              )
              .orWhere(
                searchKeyword != null && searchKeyword != ""
                  ? `orgChild2.orgChild2Name  like '%${searchKeyword}%'`
                  : "1=1",
              )
              .orWhere(
                searchKeyword != null && searchKeyword != ""
                  ? `orgChild3.orgChild3Name  like '%${searchKeyword}%'`
                  : "1=1",
              )
              .orWhere(
                searchKeyword != null && searchKeyword != ""
                  ? `orgChild4.orgChild4Name  like '%${searchKeyword}%'`
                  : "1=1",
              )
              .orWhere(
                searchKeyword != null && searchKeyword != ""
                  ? `CONCAT(
                orgRoot.orgRootShortName," ",
                current_holders.posMasterNo
                )  like '%${searchKeyword}%'`
                  : "1=1",
              )
              .orWhere(
                searchKeyword != null && searchKeyword != ""
                  ? `CONCAT(
                orgRoot.orgRootShortName,
                orgChild1.orgChild1ShortName," ",
                current_holders.posMasterNo
                )  like '%${searchKeyword}%'`
                  : "1=1",
              )
              .orWhere(
                searchKeyword != null && searchKeyword != ""
                  ? `CONCAT(
                orgRoot.orgRootShortName,
                orgChild1.orgChild1ShortName,
                orgChild2.orgChild2ShortName," ",
                current_holders.posMasterNo
                )  like '%${searchKeyword}%'`
                  : "1=1",
              )
              .orWhere(
                searchKeyword != null && searchKeyword != ""
                  ? `CONCAT(
                orgRoot.orgRootShortName,
                orgChild1.orgChild1ShortName,
                orgChild2.orgChild2ShortName,
                orgChild3.orgChild3ShortName," ",
                current_holders.posMasterNo
                )  like '%${searchKeyword}%'`
                  : "1=1",
              )
              .orWhere(
                searchKeyword != null && searchKeyword != ""
                  ? `CONCAT(
                orgRoot.orgRootShortName,
                orgChild1.orgChild1ShortName,
                orgChild2.orgChild2ShortName,
                orgChild3.orgChild3ShortName,
                orgChild4.orgChild4ShortName," ",
                current_holders.posMasterNo
                )  like '%${searchKeyword}%'`
                  : "1=1",
              )
              .orWhere(
                searchKeyword != null && searchKeyword != ""
                  ? `CONCAT(
                orgRoot.orgRootShortName,
                current_holders.posMasterNo
                )  like '%${searchKeyword}%'`
                  : "1=1",
              )
              .orWhere(
                searchKeyword != null && searchKeyword != ""
                  ? `CONCAT(
                orgRoot.orgRootShortName,
                orgChild1.orgChild1ShortName,
                current_holders.posMasterNo
                )  like '%${searchKeyword}%'`
                  : "1=1",
              )
              .orWhere(
                searchKeyword != null && searchKeyword != ""
                  ? `CONCAT(
                orgRoot.orgRootShortName,
                orgChild1.orgChild1ShortName,
                orgChild2.orgChild2ShortName,
                current_holders.posMasterNo
                )  like '%${searchKeyword}%'`
                  : "1=1",
              )
              .orWhere(
                searchKeyword != null && searchKeyword != ""
                  ? `CONCAT(
                orgRoot.orgRootShortName,
                orgChild1.orgChild1ShortName,
                orgChild2.orgChild2ShortName,
                orgChild3.orgChild3ShortName,
                current_holders.posMasterNo
                )  like '%${searchKeyword}%'`
                  : "1=1",
              )
              .orWhere(
                searchKeyword != null && searchKeyword != ""
                  ? `CONCAT(
                orgRoot.orgRootShortName,
                orgChild1.orgChild1ShortName,
                orgChild2.orgChild2ShortName,
                orgChild3.orgChild3ShortName,
                orgChild4.orgChild4ShortName,
                current_holders.posMasterNo
                )  like '%${searchKeyword}%'`
                  : "1=1",
              );
          }),
        )
        // .andWhere(
        //   rootId != undefined &&
        //   rootId != null
        //   ? `current_holders.orgRootId = :rootId`
        //   : "1=1",
        //   {
        //   rootId: rootId,
        //   }
        // )
        .andWhere("current_holders.orgRootId = :rootId", {
          rootId: rootId,
        })
        .addSelect("CASE WHEN current_holders.posMasterNo IS NULL THEN 1 ELSE 0 END", "sort_order");
      // .orderBy(`${sortBy}`, sort)

      if (sortBy) {
        if (sortBy == "posLevel") {
          query = query.orderBy(`posLevel.posLevelName`, descending ? "DESC" : "ASC");
        } else if (sortBy == "posType") {
          query = query.orderBy(`posType.posTypeName`, descending ? "DESC" : "ASC");
        } else if (sortBy == "posExecutive") {
          query = query.orderBy(`posExecutive.posExecutiveName`, descending ? "DESC" : "ASC");
        } else if (sortBy == "posNo") {
          query = query
            .orderBy("orgChild4.orgChild4ShortName", descending ? "DESC" : "ASC")
            .addOrderBy("orgChild3.orgChild3ShortName", descending ? "DESC" : "ASC")
            .addOrderBy("orgChild2.orgChild2ShortName", descending ? "DESC" : "ASC")
            .addOrderBy("orgChild1.orgChild1ShortName", descending ? "DESC" : "ASC")
            .addOrderBy("orgRoot.orgRootShortName", descending ? "DESC" : "ASC")
            .addOrderBy("current_holders.posMasterNo", descending ? "DESC" : "ASC");
        } else {
          query = query.orderBy(`profile.${sortBy}`, descending ? "DESC" : "ASC");
        }
      } else {
        query = query
          .orderBy("sort_order", "ASC")
          .addOrderBy("orgRoot.orgRootOrder", "ASC")
          .addOrderBy("orgChild1.orgChild1Order", "ASC")
          .addOrderBy("orgChild2.orgChild2Order", "ASC")
          .addOrderBy("orgChild3.orgChild3Order", "ASC")
          .addOrderBy("orgChild4.orgChild4Order", "ASC")
          .addOrderBy("current_holders.posMasterNo", "ASC");
      }

      const [record, total] = await query
        .skip((page - 1) * pageSize)
        .take(pageSize)
        .getManyAndCount();

      const data = await Promise.all(
        record.map((_data) => {
          const posExecutive =
            _data.current_holders.length == 0 ||
            _data.current_holders.find((x) => x.orgRevisionId == findRevision.id) == null ||
            _data.current_holders.find((x) => x.orgRevisionId == findRevision.id)?.positions
              .length == 0 ||
            _data.current_holders
              .find((x) => x.orgRevisionId == findRevision.id)
              ?.positions.find((x: any) => x.positionIsSelected == true) == null ||
            _data.current_holders
              .find((x) => x.orgRevisionId == findRevision.id)
              ?.positions.find((x: any) => x.positionIsSelected == true)?.posExecutive == null
              ? null
              : _data.current_holders
                  .find((x) => x.orgRevisionId == findRevision.id)
                  ?.positions.find((x: any) => x.positionIsSelected == true)?.posExecutive
                  ?.posExecutiveName;

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

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

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

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

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

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

          return {
            id: _data.id,
            avatar: _data.avatar,
            avatarName: _data.avatarName,
            prefix: _data.prefix,
            rank: _data.rank,
            firstName: _data.firstName,
            lastName: _data.lastName,
            citizenId: _data.citizenId,
            posLevel: _data.posLevel == null ? null : _data.posLevel.posLevelName,
            posType: _data.posType == null ? null : _data.posType.posTypeName,
            posLevelId: _data.posLevel == null ? null : _data.posLevel.id,
            posTypeId: _data.posType == null ? null : _data.posType.id,
            position: _data.position,
            posExecutive: posExecutive,
            posNo: shortName,
            rootId: root == null ? null : root.id,
            root: root == null ? null : root.orgRootName,
            orgRootShortName: root == null ? null : root.orgRootShortName,
            orgRevisionId: root == null ? null : root.orgRevisionId,
            org:
              (_child4 == null ? "" : _child4 + "\n") +
              (_child3 == null ? "" : _child3 + "\n") +
              (_child2 == null ? "" : _child2 + "\n") +
              (_child1 == null ? "" : _child1 + "\n") +
              (root?.orgRootName == null ? "" : root?.orgRootName),
            statusCheckEdit: _data.statusCheckEdit,
            type: "OFFICER",
          };
        }),
      );

      return new HttpSuccess({ data: data, total });
    } else {
      let _data = await new permission().PermissionOrgList(request, "SYS_REGISTRY_EMP");
      let queryLike =
        "CONCAT(profileEmployee.prefix, profileEmployee.firstName, ' ', profileEmployee.lastName) LIKE :keyword";
      if (searchField == "citizenId") {
        queryLike = "profileEmployee.citizenId LIKE :keyword";
      }
      const findRevision = await this.orgRevisionRepo.findOne({
        where: { orgRevisionIsCurrent: true },
      });
      if (!findRevision) {
        throw new HttpError(HttpStatus.NOT_FOUND, "not found. OrgRevision");
      }
      let query = await this.profileEmployeeRepo
        .createQueryBuilder("profileEmployee")
        .leftJoinAndSelect("profileEmployee.posLevel", "posLevel")
        .leftJoinAndSelect("profileEmployee.posType", "posType")
        .leftJoinAndSelect("profileEmployee.current_holders", "current_holders")
        .leftJoinAndSelect("profileEmployee.profileEmployeeEmployment", "profileEmployeeEmployment")
        .leftJoinAndSelect("current_holders.positions", "positions")
        .leftJoinAndSelect("current_holders.orgRevision", "orgRevision")
        .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")
        .where("current_holders.orgRevisionId = :orgRevisionId", {
          orgRevisionId: findRevision.id,
        })
        .andWhere(
          statusCheckEdit != undefined &&
            statusCheckEdit != null &&
            statusCheckEdit.toUpperCase() != "ALL"
            ? "profileEmployee.statusCheckEdit = :statusCheckEdit"
            : "1=1",
          {
            statusCheckEdit: statusCheckEdit?.trim()?.toUpperCase() ?? null,
          },
        )
        .andWhere(
          _data.root != undefined && _data.root != null
            ? _data.root[0] != null
              ? `current_holders.orgRootId IN (:...root)`
              : `current_holders.orgRootId is null`
            : "1=1",
          {
            root: _data.root,
          },
        )
        .andWhere(
          _data.child1 != undefined && _data.child1 != null
            ? _data.child1[0] != null
              ? `current_holders.orgChild1Id IN (:...child1)`
              : // : `current_holders.orgChild1Id is ${_data.privilege == "PARENT" ? "not null" : "null"}`
                `current_holders.orgChild1Id is null`
            : "1=1",
          {
            child1: _data.child1,
          },
        )
        .andWhere(
          _data.child2 != undefined && _data.child2 != null
            ? _data.child2[0] != null
              ? `current_holders.orgChild2Id IN (:...child2)`
              : `current_holders.orgChild2Id is null`
            : "1=1",
          {
            child2: _data.child2,
          },
        )
        .andWhere(
          _data.child3 != undefined && _data.child3 != null
            ? _data.child3[0] != null
              ? `current_holders.orgChild3Id IN (:...child3)`
              : `current_holders.orgChild3Id is null`
            : "1=1",
          {
            child3: _data.child3,
          },
        )
        .andWhere(
          _data.child4 != undefined && _data.child4 != null
            ? _data.child4[0] != null
              ? `current_holders.orgChild4Id IN (:...child4)`
              : `current_holders.orgChild4Id is null`
            : "1=1",
          {
            child4: _data.child4,
          },
        )
        // .andWhere("profileEmployee.employeeClass LIKE :type", {
        //   type: "PERM",
        // })
        // .andWhere(
        //   searchKeyword != undefined && searchKeyword != null && searchKeyword != ""
        //     ? queryLike
        //     : "1=1",
        //   {
        //     keyword: `%${searchKeyword}%`,
        //   },
        // )
        .andWhere(
          new Brackets((qb) => {
            qb.orWhere(
              searchKeyword != null && searchKeyword != ""
                ? `profileEmployee.citizenId like '%${searchKeyword}%'`
                : "1=1",
            )
              .orWhere(
                searchKeyword != null && searchKeyword != ""
                  ? `profileEmployee.position like '%${searchKeyword}%'`
                  : "1=1",
              )
              .orWhere(
                searchKeyword != null && searchKeyword != ""
                  ? `CONCAT(profileEmployee.prefix, profileEmployee.firstName," ",profileEmployee.lastName)  like '%${searchKeyword}%'`
                  : "1=1",
              )
              .orWhere(
                searchKeyword != null && searchKeyword != ""
                  ? `posType.posTypeName like '%${searchKeyword}%'`
                  : "1=1",
              )
              .orWhere(
                searchKeyword != null && searchKeyword != ""
                  ? `posLevel.posLevelName  like '%${searchKeyword}%'`
                  : "1=1",
              )
              .orWhere(
                searchKeyword != null && searchKeyword != ""
                  ? `CONCAT(posType.posTypeShortName," ",posLevel.posLevelName)  like '%${searchKeyword}%'`
                  : "1=1",
              )
              .orWhere(
                searchKeyword != null && searchKeyword != ""
                  ? `CONCAT(posType.posTypeShortName,posLevel.posLevelName)  like '%${searchKeyword}%'`
                  : "1=1",
              )
              .orWhere(
                searchKeyword != null && searchKeyword != ""
                  ? `orgRoot.orgRootName  like '%${searchKeyword}%'`
                  : "1=1",
              )
              .orWhere(
                searchKeyword != null && searchKeyword != ""
                  ? `orgChild1.orgChild1Name  like '%${searchKeyword}%'`
                  : "1=1",
              )
              .orWhere(
                searchKeyword != null && searchKeyword != ""
                  ? `orgChild2.orgChild2Name  like '%${searchKeyword}%'`
                  : "1=1",
              )
              .orWhere(
                searchKeyword != null && searchKeyword != ""
                  ? `orgChild3.orgChild3Name  like '%${searchKeyword}%'`
                  : "1=1",
              )
              .orWhere(
                searchKeyword != null && searchKeyword != ""
                  ? `orgChild4.orgChild4Name  like '%${searchKeyword}%'`
                  : "1=1",
              )
              .orWhere(
                searchKeyword != null && searchKeyword != ""
                  ? `CONCAT(
                orgRoot.orgRootShortName," ",
                current_holders.posMasterNo
                )  like '%${searchKeyword}%'`
                  : "1=1",
              )
              .orWhere(
                searchKeyword != null && searchKeyword != ""
                  ? `CONCAT(
                orgRoot.orgRootShortName,
                orgChild1.orgChild1ShortName," ",
                current_holders.posMasterNo
                )  like '%${searchKeyword}%'`
                  : "1=1",
              )
              .orWhere(
                searchKeyword != null && searchKeyword != ""
                  ? `CONCAT(
                orgRoot.orgRootShortName,
                orgChild1.orgChild1ShortName,
                orgChild2.orgChild2ShortName," ",
                current_holders.posMasterNo
                )  like '%${searchKeyword}%'`
                  : "1=1",
              )
              .orWhere(
                searchKeyword != null && searchKeyword != ""
                  ? `CONCAT(
                orgRoot.orgRootShortName,
                orgChild1.orgChild1ShortName,
                orgChild2.orgChild2ShortName,
                orgChild3.orgChild3ShortName," ",
                current_holders.posMasterNo
                )  like '%${searchKeyword}%'`
                  : "1=1",
              )
              .orWhere(
                searchKeyword != null && searchKeyword != ""
                  ? `CONCAT(
                orgRoot.orgRootShortName,
                orgChild1.orgChild1ShortName,
                orgChild2.orgChild2ShortName,
                orgChild3.orgChild3ShortName,
                orgChild4.orgChild4ShortName," ",
                current_holders.posMasterNo
                )  like '%${searchKeyword}%'`
                  : "1=1",
              )
              .orWhere(
                searchKeyword != null && searchKeyword != ""
                  ? `CONCAT(
                orgRoot.orgRootShortName,
                current_holders.posMasterNo
                )  like '%${searchKeyword}%'`
                  : "1=1",
              )
              .orWhere(
                searchKeyword != null && searchKeyword != ""
                  ? `CONCAT(
                orgRoot.orgRootShortName,
                orgChild1.orgChild1ShortName,
                current_holders.posMasterNo
                )  like '%${searchKeyword}%'`
                  : "1=1",
              )
              .orWhere(
                searchKeyword != null && searchKeyword != ""
                  ? `CONCAT(
                orgRoot.orgRootShortName,
                orgChild1.orgChild1ShortName,
                orgChild2.orgChild2ShortName,
                current_holders.posMasterNo
                )  like '%${searchKeyword}%'`
                  : "1=1",
              )
              .orWhere(
                searchKeyword != null && searchKeyword != ""
                  ? `CONCAT(
                orgRoot.orgRootShortName,
                orgChild1.orgChild1ShortName,
                orgChild2.orgChild2ShortName,
                orgChild3.orgChild3ShortName,
                current_holders.posMasterNo
                )  like '%${searchKeyword}%'`
                  : "1=1",
              )
              .orWhere(
                searchKeyword != null && searchKeyword != ""
                  ? `CONCAT(
                orgRoot.orgRootShortName,
                orgChild1.orgChild1ShortName,
                orgChild2.orgChild2ShortName,
                orgChild3.orgChild3ShortName,
                orgChild4.orgChild4ShortName,
                current_holders.posMasterNo
                )  like '%${searchKeyword}%'`
                  : "1=1",
              );
          }),
        )
        .andWhere("current_holders.orgRootId = :rootId", {
          rootId: rootId,
        })
        .orderBy("current_holders.posMasterNo", "ASC");
      // .orderBy(`${sortBy}`, sort)

      if (sortBy) {
        if (sortBy == "posLevel") {
          query = query.orderBy(`posLevel.posLevelName`, descending ? "DESC" : "ASC");
        } else if (sortBy == "posType") {
          query = query.orderBy(`posType.posTypeName`, descending ? "DESC" : "ASC");
        } else if (sortBy == "posNo") {
          query = query.orderBy(`orgRoot.orgRootShortName`, descending ? "DESC" : "ASC");
        } else {
          query = query.orderBy(`profileEmployee.${sortBy}`, descending ? "DESC" : "ASC");
        }
      }
      const [record, total] = await query
        .skip((page - 1) * pageSize)
        .take(pageSize)
        .getManyAndCount();

      const data = await Promise.all(
        record.map((_data) => {
          const shortName =
            _data.current_holders.length == 0
              ? null
              : _data.current_holders.find((x) => x.orgRevisionId == findRevision.id) != null &&
                  _data.current_holders.find((x) => x.orgRevisionId == findRevision.id)
                    ?.orgChild4 != null
                ? `${_data.current_holders.find((x) => x.orgRevisionId == findRevision.id)?.orgChild4.orgChild4ShortName} ${_data.current_holders.find((x) => x.orgRevisionId == findRevision.id)?.posMasterNo}`
                : _data.current_holders.find((x) => x.orgRevisionId == findRevision.id) != null &&
                    _data.current_holders.find((x) => x.orgRevisionId == findRevision.id)
                      ?.orgChild3 != null
                  ? `${_data.current_holders.find((x) => x.orgRevisionId == findRevision.id)?.orgChild3.orgChild3ShortName} ${_data.current_holders.find((x) => x.orgRevisionId == findRevision.id)?.posMasterNo}`
                  : _data.current_holders.find((x) => x.orgRevisionId == findRevision.id) != null &&
                      _data.current_holders.find((x) => x.orgRevisionId == findRevision.id)
                        ?.orgChild2 != null
                    ? `${_data.current_holders.find((x) => x.orgRevisionId == findRevision.id)?.orgChild2.orgChild2ShortName} ${_data.current_holders.find((x) => x.orgRevisionId == findRevision.id)?.posMasterNo}`
                    : _data.current_holders.find((x) => x.orgRevisionId == findRevision.id) !=
                          null &&
                        _data.current_holders.find((x) => x.orgRevisionId == findRevision.id)
                          ?.orgChild1 != null
                      ? `${_data.current_holders.find((x) => x.orgRevisionId == findRevision.id)?.orgChild1.orgChild1ShortName} ${_data.current_holders.find((x) => x.orgRevisionId == findRevision.id)?.posMasterNo}`
                      : _data.current_holders.find((x) => x.orgRevisionId == findRevision.id) !=
                            null &&
                          _data.current_holders.find((x) => x.orgRevisionId == findRevision.id)
                            ?.orgRoot != null
                        ? `${_data.current_holders.find((x) => x.orgRevisionId == findRevision.id)?.orgRoot.orgRootShortName} ${_data.current_holders.find((x) => x.orgRevisionId == findRevision.id)?.posMasterNo}`
                        : null;
          const dateEmployment =
            _data.profileEmployeeEmployment.length == 0
              ? null
              : _data.profileEmployeeEmployment.reduce((latest, current) => {
                  return latest.date > current.date ? latest : current;
                }).date;
          const root =
            _data.current_holders.length == 0 ||
            (_data.current_holders.find((x) => x.orgRevisionId == findRevision.id) != null &&
              _data.current_holders.find((x) => x.orgRevisionId == findRevision.id)?.orgRoot ==
                null)
              ? null
              : _data.current_holders.find((x) => x.orgRevisionId == findRevision.id)?.orgRoot;

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

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

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

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

          let _child1 = child1?.orgChild1Name;
          let _child2 = child2?.orgChild2Name;
          let _child3 = child3?.orgChild3Name;
          let _child4 = child4?.orgChild4Name;
          return {
            id: _data.id,
            prefix: _data.prefix,
            rank: _data.rank,
            firstName: _data.firstName,
            lastName: _data.lastName,
            citizenId: _data.citizenId,
            posLevel: _data.posLevel == null ? null : _data.posLevel.posLevelName,
            posType: _data.posType == null ? null : _data.posType.posTypeName,
            posTypeShortName: _data.posType == null ? null : _data.posType.posTypeShortName,
            posLevelId: _data.posLevel == null ? null : _data.posLevel.id,
            posTypeId: _data.posType == null ? null : _data.posType.id,
            positionId: _data.positionIdTemp,
            posmasterId: _data.posmasterIdTemp,
            position: _data.position,
            posNo: _data.employeeClass == "TEMP" ? _data.posMasterNoTemp : shortName,
            employeeClass: _data.employeeClass == null ? null : _data.employeeClass,
            govAge: Extension.CalculateGovAge(_data.dateAppoint, 0, 0),
            age: Extension.CalculateAgeStrV2(_data.birthDate, 0, 0, "GET"),
            dateEmployment: dateEmployment,
            dateAppoint: _data.dateAppoint,
            dateStart: _data.dateStart,
            createdAt: _data.createdAt,
            dateRetireLaw: _data.dateRetireLaw,
            draftOrganizationOrganization:
              _data.nodeTemp == "0"
                ? _data.rootTemp
                : _data.nodeTemp == "1"
                  ? _data.child1Temp
                  : _data.nodeTemp == "2"
                    ? _data.child2Temp
                    : _data.nodeTemp == "3"
                      ? _data.child3Temp
                      : _data.nodeTemp == "4"
                        ? _data.child4Temp
                        : null,
            draftPositionEmployee: _data.positionTemp,
            draftOrgEmployeeStatus: _data.statusTemp,
            node: _data.nodeTemp,
            nodeId: _data.nodeIdTemp,
            nodeName:
              _data.nodeTemp == "0"
                ? _data.rootTemp
                : _data.nodeTemp == "1"
                  ? _data.child1Temp
                  : _data.nodeTemp == "2"
                    ? _data.child2Temp
                    : _data.nodeTemp == "3"
                      ? _data.child3Temp
                      : _data.nodeTemp == "4"
                        ? _data.child4Temp
                        : null,
            nodeShortName:
              _data.nodeTemp == "0"
                ? _data.rootShortNameTemp
                : _data.nodeTemp == "1"
                  ? _data.child1ShortNameTemp
                  : _data.nodeTemp == "2"
                    ? _data.child1ShortNameTemp
                    : _data.nodeTemp == "3"
                      ? _data.child3ShortNameTemp
                      : _data.nodeTemp == "4"
                        ? _data.child4ShortNameTemp
                        : null,
            root: _data.rootTemp ? _data.rootTemp : null,
            rootId: _data.rootIdTemp ? _data.rootIdTemp : null,
            rootShortName: _data.rootShortNameTemp ? _data.rootShortNameTemp : null,
            child1: _data.child1Temp ? _data.child1Temp : null,
            child1Id: _data.child1IdTemp ? _data.child1IdTemp : null,
            child1ShortName: _data.child1ShortNameTemp ? _data.child1ShortNameTemp : null,
            child2: _data.child2Temp ? _data.child2Temp : null,
            child2Id: _data.child2IdTemp ? _data.child2IdTemp : null,
            child2ShortName: _data.child2ShortNameTemp ? _data.child2ShortNameTemp : null,
            child3: _data.child3Temp ? _data.child3Temp : null,
            child3Id: _data.child3IdTemp ? _data.child3IdTemp : null,
            child3ShortName: _data.child3ShortNameTemp ? _data.child3ShortNameTemp : null,
            child4: _data.child4Temp ? _data.child4Temp : null,
            child4Id: _data.child4IdTemp ? _data.child4IdTemp : null,
            child4ShortName: _data.child4ShortNameTemp ? _data.child4ShortNameTemp : null,
            org:
              (_child4 == null ? "" : _child4 + "\n") +
              (_child3 == null ? "" : _child3 + "\n") +
              (_child2 == null ? "" : _child2 + "\n") +
              (_child1 == null ? "" : _child1 + "\n") +
              (root?.orgRootName == null ? "" : root?.orgRootName),
            statusCheckEdit: _data.statusCheckEdit,
            type: "EMPLOYEE",
          };
        }),
      );

      return new HttpSuccess({ data: data, total });
    }
  }

  // /**
  //  * API Clone ใหม่ตำแหน่งเงินเดือน
  //  *
  //  * @summary API Clone ใหม่ตำแหน่งเงินเดือน
  //  *
  //  */
  // @Get("{type}/new-clone/{profileId}")
  // public async newCloneSalary(
  //   @Path() profileId: string,
  //   @Path() type: string,
  //   @Request() req: RequestWithUser,
  // ) {
  //   if (type.toLocaleUpperCase() == "OFFICER") {
  //     const salary = await this.salaryRepo.find({ where: { profileId: profileId } });
  //     await this.salaryRepo.remove(salary);
  //     let salaryOld = await this.salaryOldRepo.find({
  //       where: { profileId: profileId },
  //       order: { order: "ASC" },
  //     });
  //     salaryOld.forEach((item: any) => {
  //       item.salaryId = item.id;
  //       item.order = i + 1;
  //     });
  //     let salaryNew = salaryOld.map(({ id, ...rest }: ProfileSalary) => ({
  //       ...rest,
  //       isDelete: false,
  //       isEdit: false,
  //       createdUserId: req.user.sub,
  //       createdFullName: req.user.name,
  //       lastUpdateUserId: req.user.sub,
  //       lastUpdateFullName: req.user.name,
  //       createdAt: new Date(),
  //       lastUpdatedAt: new Date(),
  //     }));
  //     await this.salaryRepo.save(salaryNew);
  //     return new HttpSuccess(salaryNew);
  //   } else {
  //     const salary = await this.salaryRepo.find({ where: { profileEmployeeId: profileId } });
  //     await this.salaryRepo.remove(salary);
  //     let salaryOld = await this.salaryOldRepo.find({
  //       where: { profileEmployeeId: profileId },
  //       order: { order: "ASC" },
  //     });
  //     salaryOld.forEach((item: any) => {
  //       item.salaryId = item.id;
  //       item.order = i + 1;
  //     });
  //     let salaryNew = salaryOld.map(({ id, ...rest }: ProfileSalary) => ({
  //       ...rest,
  //       isDelete: false,
  //       isEdit: false,
  //       createdUserId: req.user.sub,
  //       createdFullName: req.user.name,
  //       lastUpdateUserId: req.user.sub,
  //       lastUpdateFullName: req.user.name,
  //       createdAt: new Date(),
  //       lastUpdatedAt: new Date(),
  //     }));
  //     await this.salaryRepo.save(salaryNew);
  //     return new HttpSuccess(salaryNew);
  //   }
  // }

  /**
   * API Get ตำแหน่งเงินเดือน
   *
   * @summary API Get ตำแหน่งเงินเดือน
   *
   */
  @Get("get/{salaryId}")
  public async getSalary(@Path() salaryId: string, @Request() req: RequestWithUser) {
    const salary = await this.salaryRepo.findOne({
      where: { id: salaryId },
      relations: ["profileSalary"],
    });
    if (!salary) {
      throw new HttpError(HttpStatus.BAD_REQUEST, "ไม่พบ profile ดังกล่าว");
    }
    return new HttpSuccess({
      salaryNew: salary,
      salaryOld: salary.profileSalary,
    });
  }

  /**
   * API List ตำแหน่งเงินเดือน
   *
   * @summary API List ตำแหน่งเงินเดือน
   *
   */
  @Get("{type}/{profileId}")
  public async listSalary(
    @Path() profileId: string,
    @Path() type: string,
    @Request() req: RequestWithUser,
  ) {
    if (type.toLocaleUpperCase() == "OFFICER") {
      const salary = await this.salaryRepo.find({
        where: { profileId: profileId },
        order: { order: "ASC" },
      });

      if (salary.length <= 0) {
        let salaryOld = await this.salaryOldRepo.find({
          where: { profileId: profileId },
          order: { order: "ASC" },
        });
        salaryOld.forEach((item: any, i) => {
          item.salaryId = item.id;
          item.order = i + 1;
        });
        let salaryNew = salaryOld.map(({ id, ...rest }: ProfileSalary) => ({
          ...rest,
          isDelete: false,
          isEdit: false,
          isEntry: rest.isEntry ?? false,
          createdUserId: req.user.sub,
          createdFullName: req.user.name,
          lastUpdateUserId: req.user.sub,
          lastUpdateFullName: req.user.name,
          createdAt: new Date(),
          lastUpdatedAt: new Date(),
        }));
        await this.salaryRepo.save(salaryNew);
        return new HttpSuccess(
          salaryNew.map((item) => ({
            ...item,
            status: item.isDelete == true ? "DELETE" : item.isEdit == true ? "EDIT" : "PENDING",
          })),
        );
      }
      return new HttpSuccess(
        salary.map((item) => ({
          ...item,
          status: item.isDelete == true ? "DELETE" : item.isEdit == true ? "EDIT" : "PENDING",
        })),
      );
    } else {
      const salary = await this.salaryRepo.find({
        where: { profileEmployeeId: profileId },
        order: { order: "ASC" },
      });
      if (salary.length <= 0) {
        let salaryOld = await this.salaryOldRepo.find({
          where: { profileEmployeeId: profileId },
          order: { order: "ASC" },
        });
        salaryOld.forEach((item: any, i) => {
          item.salaryId = item.id;
          item.order = i + 1;
        });
        let salaryNew = salaryOld.map(({ id, ...rest }: ProfileSalary) => ({
          ...rest,
          isDelete: false,
          isEdit: false,
          isEntry: rest.isEntry ?? false,
          createdUserId: req.user.sub,
          createdFullName: req.user.name,
          lastUpdateUserId: req.user.sub,
          lastUpdateFullName: req.user.name,
          createdAt: new Date(),
          lastUpdatedAt: new Date(),
        }));
        await this.salaryRepo.save(salaryNew);
        return new HttpSuccess(
          salaryNew.map((item) => ({
            ...item,
            status: item.isDelete == true ? "DELETE" : item.isEdit == true ? "EDIT" : "PENDING",
          })),
        );
      }
      return new HttpSuccess(
        salary.map((item) => ({
          ...item,
          status: item.isDelete == true ? "DELETE" : item.isEdit == true ? "EDIT" : "PENDING",
        })),
      );
    }
  }

  /**
   * API List ตำแหน่งเงินเดือนแก้ไขแล้ว
   *
   * @summary API List ตำแหน่งเงินเดือนแก้ไขแล้ว
   *
   */
  @Get("{type}/done/{profileId}")
  public async listDoneSalary(
    @Path() profileId: string,
    @Path() type: string,
    @Request() req: RequestWithUser,
  ) {
    if (type.toLocaleUpperCase() == "OFFICER") {
      const salary = await this.salaryRepo.find({
        where: { profileId: profileId, isDelete: false },
        order: { order: "ASC" },
      });
      if (!salary) {
        throw new HttpError(HttpStatus.BAD_REQUEST, "ไม่พบ profile ดังกล่าว");
      }
      return new HttpSuccess(
        salary.map((item) => ({
          ...item,
          status: item.isDelete == true ? "DELETE" : item.isEdit == true ? "EDIT" : "PENDING",
        })),
      );
    } else {
      const salary = await this.salaryRepo.find({
        where: { profileEmployeeId: profileId, isDelete: false },
        order: { order: "ASC" },
      });
      if (!salary) {
        throw new HttpError(HttpStatus.BAD_REQUEST, "ไม่พบ profile ดังกล่าว");
      }
      return new HttpSuccess(
        salary.map((item) => ({
          ...item,
          status: item.isDelete == true ? "DELETE" : item.isEdit == true ? "EDIT" : "PENDING",
        })),
      );
    }
  }

  /**
   * API สร้างตำแหน่งเงินเดือน
   *
   * @summary API สร้างตำแหน่งเงินเดือน
   *
   */
  @Post()
  public async newSalary(@Request() req: RequestWithUser, @Body() body: CreateProfileSalaryTemp) {
    let dest_item = 1;

    if (body.type.toLocaleUpperCase() == "OFFICER") {
      if (body.profileId) {
        const salary = await this.salaryRepo.findOne({
          where: { profileId: body.profileId },
          order: { order: "DESC" },
        });
        if (salary) {
          dest_item = salary.order + 1;
        }
        // const profile = await this.profileRepo.findOneBy({ id: body.profileId });
        // if (!profile) {
        //   throw new HttpError(HttpStatus.BAD_REQUEST, "ไม่พบ profile ดังกล่าว");
        // }
        // profile.statusCheckEdit = "EDITED"
        // await this.profileRepo.save(profile);
      } else {
        throw new HttpError(HttpStatus.BAD_REQUEST, "ไม่พบ profile ดังกล่าว");
      }
    } else {
      if (body.profileEmployeeId) {
        const salary = await this.salaryRepo.findOne({
          where: { profileEmployeeId: body.profileEmployeeId },
          order: { order: "DESC" },
        });
        if (salary) {
          dest_item = salary.order + 1;
        }
        // const profile = await this.profileEmployeeRepo.findOneBy({ id: body.profileId });
        // if (!profile) {
        //   throw new HttpError(HttpStatus.BAD_REQUEST, "ไม่พบ profile ดังกล่าว");
        // }
        // profile.statusCheckEdit = "EDITED"
        // await this.profileRepo.save(profile);
      } else {
        throw new HttpError(HttpStatus.BAD_REQUEST, "ไม่พบ profile ดังกล่าว");
      }
    }
    const before = null;
    const data = new ProfileSalaryTemp();

    const meta = {
      order: dest_item,
      createdUserId: req.user.sub,
      createdFullName: req.user.name,
      lastUpdateUserId: req.user.sub,
      lastUpdateFullName: req.user.name,
      createdAt: new Date(),
      lastUpdatedAt: new Date(),
      isEdit: true,
      isDelete: false,
    };
    Object.assign(data, { ...body, ...meta });
    // if (["12", "15", "16"].includes(body.commandCode ?? "")) {
    //   data.isGovernment = false;
    //   if (body.commandDateAffect) data.dateGovernment = body.commandDateAffect;
    // } else if (["1", "2", "3", "4", "10", "11", "20"].includes(body.commandCode ?? "")) {
    //   data.isGovernment = true;
    //   if (body.commandDateAffect) data.dateGovernment = body.commandDateAffect;
    // }
    await this.salaryRepo.save(data, { data: req });
    setLogDataDiff(req, { before, after: data });

    return new HttpSuccess();
  }

  /**
   * API แก้สถานะเป็นยังไม่แก้ไข
   *
   * @summary API แก้สถานะเป็นยังไม่แก้ไข
   *
   */
  @Post("confirm-pending")
  public async confirmPendingSalary(
    @Request() req: RequestWithUser,
    @Body() body: { profileId: string; type: string },
  ) {
    if (body.type.toLocaleUpperCase() == "OFFICER") {
      const profile = await this.profileRepo.findOneBy({ id: body.profileId });
      if (!profile) {
        throw new HttpError(HttpStatus.BAD_REQUEST, "ไม่พบ profile ดังกล่าว");
      }
      profile.statusCheckEdit = "PENDING";
      await this.profileRepo.save(profile);
    } else {
      const profile = await this.profileEmployeeRepo.findOneBy({
        id: body.profileId,
      });
      if (!profile) {
        throw new HttpError(HttpStatus.BAD_REQUEST, "ไม่พบ profile ดังกล่าว");
      }
      profile.statusCheckEdit = "PENDING";
      await this.profileEmployeeRepo.save(profile);
    }
    return new HttpSuccess();
  }

  /**
   * API ยืนยันเสร็จสิ้นการแก้ไข
   *
   * @summary API ยืนยันเสร็จสิ้นการแก้ไข
   *
   */
  @Post("confirm-edit")
  public async confirmEditSalary(
    @Request() req: RequestWithUser,
    @Body() body: { profileId: string; type: string },
  ) {
    if (body.type.toLocaleUpperCase() == "OFFICER") {
      const profile = await this.profileRepo.findOneBy({ id: body.profileId });
      if (!profile) {
        throw new HttpError(HttpStatus.BAD_REQUEST, "ไม่พบ profile ดังกล่าว");
      }
      profile.statusCheckEdit = "EDITED";
      await this.profileRepo.save(profile);
    } else {
      const profile = await this.profileEmployeeRepo.findOneBy({
        id: body.profileId,
      });
      if (!profile) {
        throw new HttpError(HttpStatus.BAD_REQUEST, "ไม่พบ profile ดังกล่าว");
      }
      profile.statusCheckEdit = "EDITED";
      await this.profileEmployeeRepo.save(profile);
    }
    return new HttpSuccess();
  }

  /**
   * API ยืนยันข้อมูลถูกต้อง
   *
   * @summary API ยืนยันข้อมูลถูกต้อง
   *
   */
  @Post("confirm-done")
  public async confirmDoneSalary(
    @Request() req: RequestWithUser,
    @Body() body: ConfirmDoneSalaryDto,
  ) {
    const queryRunner = AppDataSource.createQueryRunner();
    await queryRunner.connect();
    await queryRunner.startTransaction();

    try {
      const isOfficer = body.type.toUpperCase() === "OFFICER";

      /* =========================
       * 1. Load Profile
       * ========================= */
      const profile = isOfficer
        ? await queryRunner.manager.findOne(Profile, {
            where: { id: body.profileId },
          })
        : await queryRunner.manager.findOne(ProfileEmployee, {
            where: { id: body.profileId },
          });

      if (!profile) {
        throw new HttpError(HttpStatus.BAD_REQUEST, "ไม่พบข้อมูล profile");
      }

      profile.statusCheckEdit = "CHECKED";
      await queryRunner.manager.save(profile);

      /* =========================
       * 2. Load Salary Temp
       * ========================= */
      const salaryTemps = await queryRunner.manager.find(ProfileSalaryTemp, {
        where: isOfficer ? { profileId: body.profileId } : { profileEmployeeId: body.profileId },
      });

      if (salaryTemps.length === 0) {
        throw new HttpError(HttpStatus.NOT_FOUND, "ไม่พบข้อมูลตำแหน่ง/เงินเดือนของ profile นี้");
      }

      /* =========================
       * 3. สำรองข้อมูล Temp ไว้ restore ภายหลัง
       * ========================= */
      const originalTempRows = salaryTemps; // เก็บไว้ restore หลัง insert ProfileSalary เสร็จ
      const toInsert = salaryTemps.filter((t) => !t.isDelete);

      /* =========================
       * 4. ลบข้อมูล ProfileSalaryTemp และ ProfileSalary ปัจจุบัน
       * ========================= */
      await queryRunner.manager.delete(ProfileSalaryTemp, {
        ...(isOfficer ? { profileId: body.profileId } : { profileEmployeeId: body.profileId }),
      });

      // backup profile salary before delete
      const profileSalaryBeforeDelete = await queryRunner.manager.find(ProfileSalary, {
        where: {
          ...(isOfficer ? { profileId: body.profileId } : { profileEmployeeId: body.profileId }),
        },
      });

      // insert ProfileSalary backup to ProfileSalaryBackup
      if (profileSalaryBeforeDelete.length > 0) {
        const backupRows = profileSalaryBeforeDelete.map(({ id, ...salary }) =>
          queryRunner.manager.create(ProfileSalaryBackup, {
            ...salary,
            profileSalaryId: id,
          }),
        );
        await queryRunner.manager.insert(ProfileSalaryBackup, backupRows);
      }

      // delete profile salary
      await queryRunner.manager.delete(ProfileSalary, {
        ...(isOfficer ? { profileId: body.profileId } : { profileEmployeeId: body.profileId }),
      });

      /* =========================
       * 5. INSERT (bulk)
       * ========================= */
      if (toInsert.length > 0) {
        const dateNow = new Date();
        const metaCreated = {
          createdUserId: req.user.sub,
          createdFullName: req.user.name,
          createdAt: dateNow,
          lastUpdateUserId: req.user.sub,
          lastUpdateFullName: req.user.name,
          lastUpdatedAt: dateNow,
        };

        // แยกข้อมูลตามประเภทการ insert
        const { salaryRows, actPositionRows, assistanceRows } = toInsert.reduce<{
          salaryRows: ProfileSalaryTemp[];
          actPositionRows: ProfileSalaryTemp[];
          assistanceRows: ProfileSalaryTemp[];
        }>(
          (acc, x) => {
            if (x.commandCode === SALARY_COMMAND_CODES.ACT_POSITION) acc.actPositionRows.push(x);
            else if (x.commandCode === SALARY_COMMAND_CODES.ASSISTANCE) acc.assistanceRows.push(x);
            else acc.salaryRows.push(x);
            return acc;
          },
          { salaryRows: [], actPositionRows: [], assistanceRows: [] },
        );

        // Insert ProfileSalary
        if (salaryRows.length) {
          await queryRunner.manager.insert(
            ProfileSalary,
            salaryRows.map(({ id, ...data }) => ({
              ...data,
              ...metaCreated,
            })),
          );
        }

        // Insert ProfileActposition
        if (actPositionRows.length) {
          await queryRunner.manager.insert(
            ProfileActposition,
            actPositionRows.map((x) => ({
              profileId: x.profileId,
              profileEmployeeId: x.profileEmployeeId,
              dateStart: x.commandDateAffect,
              dateEnd: null,
              posNo: `${x.posNoAbb ?? ""} ${x.posNo ?? ""}`.trim(),
              position: x.positionName,
              commandId: x.commandId,
              refCommandNo: [x.commandNo, x.commandYear].filter(Boolean).join("/") || undefined,
              refCommandDate: x.commandDateAffect,
              status: false,
              isDeleted: false,
              ...metaCreated,
            })),
          );
        }

        // Insert ProfileAssistance
        if (assistanceRows.length) {
          await queryRunner.manager.insert(
            ProfileAssistance,
            assistanceRows.map((x) => ({
              profileId: x.profileId,
              profileEmployeeId: x.profileEmployeeId,
              agency: x.orgRoot,
              dateStart: x.commandDateAffect,
              dateEnd: null,
              commandId: x.commandId,
              commandNo: [x.commandNo, x.commandYear].filter(Boolean).join("/") || undefined,
              commandName: x.commandName ?? "ให้ช่วยราชการ",
              refCommandDate: x.commandDateSign,
              refId: x.refId,
              status: "DONE",
              isUpload: false,
              ...metaCreated,
            })),
          );
        }
      }

      /* =========================
       * Restore ProfileSalaryTemp (หลังจาก ProfileSalary insert เรียบร้อยแล้ว)
       * ========================= */
      if (originalTempRows.length > 0) {
        await queryRunner.manager.insert(
          ProfileSalaryTemp,
          originalTempRows.map(({ id, ...data }) => ({
            ...data,
            salaryId: null,
          })),
        );
      }

      await queryRunner.commitTransaction();
      return new HttpSuccess();
    } catch (error) {
      await queryRunner.rollbackTransaction();
      throw error;
    } finally {
      await queryRunner.release();
    }
  }

  /**
   * API แก้ไขข้อมูล
   *
   * @summary API แก้ไขข้อมูล
   *
   */
  @Patch("{salaryId}")
  public async editSalary(
    @Request() req: RequestWithUser,
    @Body() body: UpdateProfileSalaryTemp,
    @Path() salaryId: string,
  ) {
    const record = await this.salaryRepo.findOneBy({ id: salaryId });
    if (!record) throw new HttpError(HttpStatus.NOT_FOUND, "ไม่พบข้อมูล");
    // await new permission().PermissionOrgUserUpdate(req, "SYS_REGISTRY_OFFICER", record.profileId);
    const before = structuredClone(record);

    Object.assign(record, body);
    // 12,15,16 isGovernment = false & dateGovernment = commandDateAffect
    if (["12", "15", "16"].includes(body.commandCode ?? "")) {
      record.isGovernment = false;
      if (body.commandDateAffect) record.dateGovernment = body.commandDateAffect;
    }
    // 1,2,3,4,10,11,20 isGovernment = true & dateGovernment = commandDateAffect
    else if (["1", "2", "3", "4", "10", "11", "20"].includes(body.commandCode ?? "")) {
      record.isGovernment = true;
      if (body.commandDateAffect) record.dateGovernment = body.commandDateAffect;
    }

    record.isEdit = true;
    record.lastUpdateUserId = req.user.sub;
    record.lastUpdateFullName = req.user.name;
    record.lastUpdatedAt = new Date();

    await Promise.all([
      this.salaryRepo.save(record, { data: req }),
      setLogDataDiff(req, { before, after: record }),
    ]);

    return new HttpSuccess();
  }

  /**
   * API ลบข้อมูล
   *
   * @summary API ลบข้อมูล
   *
   */
  @Post("delete")
  public async deleteIsSalary(
    @Request() req: RequestWithUser,
    @Body() body: { salaryId: string; type: string },
  ) {
    const data = await this.salaryRepo.findOneBy({ id: body.salaryId });
    if (data == null) throw new HttpError(HttpStatus.NOT_FOUND, "ไม่พบข้อมูล");
    data.isDelete = true;
    await this.salaryRepo.save(data);

    return new HttpSuccess();
  }

  /**
   * API ย้อนลบข้อมูล
   *
   * @summary API ย้อนลบข้อมูล
   *
   */
  @Post("delete-renew")
  public async deleteReNewIsSalary(
    @Request() req: RequestWithUser,
    @Body() body: { salaryId: string; type: string },
  ) {
    const data = await this.salaryRepo.findOneBy({ id: body.salaryId });
    if (data == null) throw new HttpError(HttpStatus.NOT_FOUND, "ไม่พบข้อมูล");
    data.isDelete = false;
    await this.salaryRepo.save(data);

    return new HttpSuccess();
  }

  /**
   * API สลับตำแหน่ง
   *
   * @summary API สลับตำแหน่ง
   *
   */
  @Get("swap/{direction}/{salaryId}")
  public async swapSalary(
    @Path() direction: string,
    salaryId: string,
    @Request() req: RequestWithUser,
  ) {
    const source_item = await this.salaryRepo.findOne({
      where: { id: salaryId },
    });
    // if (source_item) {
    //await new permission().PermissionOrgUserGet(req,"SYS_REGISTRY_OFFICER",source_item.profileId,); //ไม่แน่ใจOFFปิดไว้ก่อน
    // }
    if (source_item == null) throw new HttpError(HttpStatus.NOT_FOUND, "ไม่พบข้อมูล");
    const sourceOrder = source_item.order;
    if (direction.trim().toUpperCase() == "UP") {
      const dest_item = await this.salaryRepo.findOne({
        where: {
          profileId: source_item.profileId,
          order: LessThan(sourceOrder),
        },
        order: { order: "DESC" },
      });
      if (dest_item == null) return new HttpSuccess();
      var destOrder = dest_item.order;
      dest_item.order = sourceOrder;
      dest_item.isEdit = true;
      source_item.order = destOrder;
      source_item.isEdit = true;
      await Promise.all([this.salaryRepo.save(source_item), this.salaryRepo.save(dest_item)]);
    } else {
      const dest_item = await this.salaryRepo.findOne({
        where: {
          profileId: source_item.profileId,
          order: MoreThan(sourceOrder),
        },
        order: { order: "ASC" },
      });
      if (dest_item == null) return new HttpSuccess();
      var destOrder = dest_item.order;
      dest_item.order = sourceOrder;
      dest_item.isEdit = true;
      source_item.order = destOrder;
      source_item.isEdit = true;
      await Promise.all([this.salaryRepo.save(source_item), this.salaryRepo.save(dest_item)]);
    }
    return new HttpSuccess();
  }

  /**
   * API ตีกลับแก้ไข
   *
   * @summary API ตีกลับแก้ไข
   *
   */
  @Patch("return-edit/{profileId}")
  public async returnEdit(
    @Path() profileId: string,
    @Body() body: CreatePositionSalaryEditHistory,
    @Request() req: RequestWithUser,
  ) {
    let profile = null;
    let profileEmployee = null;
    profile = await this.profileRepo.findOneBy({ id: profileId });

    if (!profile) {
      profileEmployee = await this.profileEmployeeRepo.findOneBy({
        id: profileId,
      });
      if (!profileEmployee) {
        throw new HttpError(HttpStatus.NOT_FOUND, "ไม่พบข้อมูล");
      }
    }

    try {
      if (profile) {
        profile.statusCheckEdit = "PENDING";
        await this.profileRepo.save(profile);
      } else if (profileEmployee) {
        profileEmployee.statusCheckEdit = "PENDING";
        await this.profileEmployeeRepo.save(profileEmployee);
      }

      const history: PositionSalaryEditHistory = Object.assign(
        new PositionSalaryEditHistory(),
        body,
      );
      if (profile) {
        history.profileId = profileId;
      } else if (profileEmployee) {
        history.profileEmployeeId = profileId;
      }
      history.returnedDate = new Date();
      history.examinerName = req.user.name;
      history.createdFullName = req.user.name;
      history.lastUpdateFullName = req.user.name;
      await this.positionSalaryEditHistoryRepo.save(history);

      return new HttpSuccess();
    } catch {
      throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่สามารถดําเนินการได้");
    }
  }

  /**
   * API รายการประวัติตีกลับแก้ไข
   *
   * @summary API รายการประวัติตีกลับแก้ไข
   *
   */
  @Get("return-edit/history/{profileId}")
  public async returnEditHistory(@Path() profileId: string) {
    try {
      let history = await this.positionSalaryEditHistoryRepo.find({
        where: { profileId: profileId },
        order: { returnedDate: "DESC" },
      });

      //EMP
      if (!history) {
        history = await this.positionSalaryEditHistoryRepo.find({
          where: { profileEmployeeId: profileId },
          order: { returnedDate: "DESC" },
        });
      }

      return new HttpSuccess(history);
    } catch {
      throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่สามารถดําเนินการได้");
    }
  }

  /**
   * API แก้้ไขลำดับรายคน
   *
   * @summary API แก้้ไขลำดับรายคน
   *
   */
  @Get("change/sort/all")
  public async changeSortEditGenAll() {
    try {
      const profiles = await this.profileRepo.find();
      let num = 1;
      for await (const item of profiles) {
        let salaryOld = await this.salaryOldRepo.find({
          where: { profileId: item.id },
          order: { commandDateAffect: "ASC", order: "ASC" },
        });

        salaryOld.forEach((item: any, i) => {
          item.order = i + 1;
        });
        num = num + 1;
        console.log(num);
        await this.salaryOldRepo.save(salaryOld);
      }

      return new HttpSuccess();
    } catch {
      throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่สามารถดําเนินการได้");
    }
  }

  /**
   * API แก้้ไขลำดับรายคน
   *
   * @summary API แก้้ไขลำดับรายคน
   *
   */
  @Get("change/sort/{profileId}")
  public async changeSortEdit(@Path() profileId: string) {
    try {
      let salaryOld = await this.salaryRepo.find({
        where: { profileId: profileId },
        order: { commandDateAffect: "ASC", order: "ASC" },
      });

      salaryOld.forEach((item: any, i) => {
        item.order = i + 1;
      });
      await this.salaryRepo.save(salaryOld);

      return new HttpSuccess();
    } catch {
      throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่สามารถดําเนินการได้");
    }
  }

  /**
   * API แก้้ไขลำดับรายคน
   *
   * @summary API แก้้ไขลำดับรายคน
   *
   */
  @Put("change/sort/{profileId}")
  public async changeSortEditAll(@Path() profileId: string, @Body() requestBody: { id: string[] }) {
    const salary = await this.salaryRepo.find({
      where: { profileId: profileId },
    });

    const sortLevel = salary.map((data) => ({
      ...data,
      order: requestBody.id.indexOf(data.id) + 1,
    }));

    await this.salaryRepo.save(sortLevel);
    return new HttpSuccess();
  }

  /**
   * API เรียงลำดับทะเบียนประวัติและเงินเดือนที่กำลังแก้ไขตามวันที่คำสั่งมีผล
   * @summary API เรียงลำดับทะเบียนประวัติและเงินเดือนที่กำลังแก้ไขตามวันที่คำสั่งมีผล
   */
  @Put("sort-order")
  public async reorderSalaryByCommandDate(
    @Request() req: RequestWithUser,
    @Body() body: { profileId: string; type: "OFFICER" | "EMPLOYEE" },
  ) {
    const isOfficer = body.type.toUpperCase() === "OFFICER";

    // Step 1: SELECT ข้อมูลตาม profileId และ type
    const salaryTemps = await this.salaryRepo.find({
      where: isOfficer ? { profileId: body.profileId } : { profileEmployeeId: body.profileId },
    });

    if (salaryTemps.length === 0) {
      throw new HttpError(HttpStatus.NOT_FOUND, "ไม่พบข้อมูลตำแหน่งเงินเดือน");
    }

    // Step 2: เรียงลำดับตาม commandDateAffect (ASC)
    // ถ้า commandDateAffect เท่ากัน ให้ใช้ order เดิมเป็น secondary sort
    const sortedSalary = salaryTemps.sort((a, b) => {
      // ถ้า commandDateAffect เป็น null ให้ถือว่าเป็นค่าน้อยสุด
      const dateA = a.commandDateAffect ? new Date(a.commandDateAffect).getTime() : 0;
      const dateB = b.commandDateAffect ? new Date(b.commandDateAffect).getTime() : 0;

      if (dateA !== dateB) {
        return dateA - dateB; // เรียงตามวันที่คำสั่งมีผล
      }

      // ถ้าวันที่เท่ากัน ให้ใช้ order เดิม
      const orderA = a.order ?? 0;
      const orderB = b.order ?? 0;
      return orderA - orderB;
    });

    // Step 3: UPDATE ฟิลด์ order ตามการเรียงใหม่
    const dateNow = new Date();
    const updatedSalary = sortedSalary.map((item, index) => ({
      ...item,
      order: index + 1,
      lastUpdateUserId: req.user.sub,
      lastUpdateFullName: req.user.name,
      lastUpdatedAt: dateNow,
    }));

    await this.salaryRepo.save(updatedSalary);

    return new HttpSuccess();
  }
}
