import {
  Controller,
  Get,
  Post,
  Put,
  Delete,
  Route,
  Security,
  Tags,
  Body,
  Path,
  Request,
  Response,
  Query,
} from "tsoa";
import { AppDataSource } from "../database/data-source";
import HttpSuccess from "../interfaces/http-success";
import HttpStatusCode from "../interfaces/http-status";
import HttpError from "../interfaces/http-error";
import { In, IsNull, Like, Not, Brackets } from "typeorm";
import {
  EmployeePosDict,
  CreateEmployeePosDict,
  UpdateEmployeePosDict,
} from "../entities/EmployeePosDict";
import { EmployeePosType } from "../entities/EmployeePosType";
import { EmployeePosLevel } from "../entities/EmployeePosLevel";
import { CreateEmployeePosMaster, EmployeePosMaster } from "../entities/EmployeePosMaster";
import { EmployeePosition } from "../entities/EmployeePosition";
import { OrgRevision } from "../entities/OrgRevision";
import { OrgRoot } from "../entities/OrgRoot";
import { OrgChild1 } from "../entities/OrgChild1";
import { OrgChild2 } from "../entities/OrgChild2";
import { OrgChild3 } from "../entities/OrgChild3";
import { OrgChild4 } from "../entities/OrgChild4";
import { ProfileEmployee } from "../entities/ProfileEmployee";
import { AuthRole } from "../entities/AuthRole";
import { RequestWithUser } from "../middlewares/user";
import permission from "../interfaces/permission";
import { setLogDataDiff } from "../interfaces/utils";
import {
  CreatePosMasterHistoryEmployee,
  CreatePosMasterHistoryOfficer,
} from "../services/PositionService";
import { PosMasterEmployeeHistory } from "../entities/PosMasterEmployeeHistory";
import { KeycloakAttributeService } from "../services/KeycloakAttributeService";
@Route("api/v1/org/employee/pos")
@Tags("Employee")
@Security("bearerAuth")
@Response(
  HttpStatusCode.INTERNAL_SERVER_ERROR,
  "เกิดข้อผิดพลาด ไม่สามารถแสดงรายการได้ กรุณาลองใหม่ในภายหลัง",
)
export class EmployeePositionController extends Controller {
  private employeePosDictRepository = AppDataSource.getRepository(EmployeePosDict);
  private employeePosTypeRepository = AppDataSource.getRepository(EmployeePosType);
  private employeePosLevelRepository = AppDataSource.getRepository(EmployeePosLevel);
  private employeePosMasterRepository = AppDataSource.getRepository(EmployeePosMaster);
  private posMasterHistoryRepository = AppDataSource.getRepository(PosMasterEmployeeHistory);
  private employeePositionRepository = AppDataSource.getRepository(EmployeePosition);
  private profileRepository = AppDataSource.getRepository(ProfileEmployee);
  private orgRevisionRepository = AppDataSource.getRepository(OrgRevision);
  private orgRootRepository = AppDataSource.getRepository(OrgRoot);
  private child1Repository = AppDataSource.getRepository(OrgChild1);
  private child2Repository = AppDataSource.getRepository(OrgChild2);
  private child3Repository = AppDataSource.getRepository(OrgChild3);
  private child4Repository = AppDataSource.getRepository(OrgChild4);
  private authRoleRepo = AppDataSource.getRepository(AuthRole);
  private keycloakAttributeService = new KeycloakAttributeService();

  /**
   * API เพิ่มตำแหน่งลูกจ้างประจำ
   *
   * @summary ORG_ - เพิ่มตำแหน่งลูกจ้างประจำ (ADMIN) #
   *
   */
  @Post("position")
  async CreateEmployeePosition(
    @Body()
    requestBody: CreateEmployeePosDict,
    @Request() request: RequestWithUser,
  ) {
    // await new permission().PermissionCreate(request, "SYS_ORG_EMP");
    const empPosDict = Object.assign(new EmployeePosDict(), requestBody);
    if (!empPosDict) {
      throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูล");
    }

    const EmpPosType = await this.employeePosTypeRepository.findOne({
      where: { id: String(requestBody.posTypeId) },
    });
    if (!EmpPosType) {
      throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูลกลุ่มงานนี้");
    }

    const EmpPosLevel = await this.employeePosLevelRepository.findOne({
      where: { id: String(requestBody.posLevelId) },
    });
    if (!EmpPosLevel) {
      throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูลระดับชั้นงานนี้");
    }

    const rowRepeated = await this.employeePosDictRepository.findOne({
      where: {
        posDictName: String(requestBody.posDictName),
        posTypeId: String(requestBody.posTypeId),
        posLevelId: String(requestBody.posLevelId),
      },
    });
    if (rowRepeated) {
      throw new HttpError(HttpStatusCode.NOT_FOUND, "ข้อมูล Row นี้มีอยู่ในระบบแล้ว");
    }
    const before = null;
    empPosDict.createdUserId = request.user.sub;
    empPosDict.createdFullName = request.user.name;
    empPosDict.createdAt = new Date();
    empPosDict.lastUpdateUserId = request.user.sub;
    empPosDict.lastUpdateFullName = request.user.name;
    empPosDict.lastUpdatedAt = new Date();
    await this.employeePosDictRepository.save(empPosDict, { data: request });
    setLogDataDiff(request, { before, after: empPosDict });
    return new HttpSuccess(empPosDict.id);
  }

  /**
   * API แก้ไขตำแหน่งลูกจ้างประจำ
   *
   * @summary แก้ไขตำแหน่งลูกจ้างประจำ (ADMIN)
   *
   */
  @Put("position/{id}")
  async updatePosition(
    @Path() id: string,
    @Body()
    requestBody: UpdateEmployeePosDict,
    @Request() request: RequestWithUser,
  ) {
    // await new permission().PermissionUpdate(request, "SYS_ORG_EMP");
    const empPosDict = await this.employeePosDictRepository.findOne({
      where: { id: id },
    });
    if (!empPosDict) {
      throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูลตำแหน่งลูกจ้างประจำนี้");
    }

    const checkEmpPosTypeId = await this.employeePosTypeRepository.findOne({
      where: { id: requestBody.posTypeId },
    });
    if (!checkEmpPosTypeId) {
      throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูลกลุ่มงานนี้");
    }

    const checkEmpPosLevelId = await this.employeePosLevelRepository.findOne({
      where: { id: requestBody.posLevelId },
    });
    if (!checkEmpPosLevelId) {
      throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูลระดับกลุ่มงานนี้");
    }

    const rowRepeated = await this.employeePosDictRepository.findOne({
      where: {
        id: Not(id),
        posDictName: requestBody.posDictName,
        posTypeId: requestBody.posTypeId,
        posLevelId: requestBody.posLevelId,
      },
    });
    if (rowRepeated) {
      throw new HttpError(HttpStatusCode.NOT_FOUND, "ข้อมูล Row นี้มีอยู่ในระบบแล้ว");
    }
    const before = structuredClone(empPosDict);
    empPosDict.lastUpdateUserId = request.user.sub;
    empPosDict.lastUpdateFullName = request.user.name;
    empPosDict.lastUpdatedAt = new Date();
    this.employeePosDictRepository.merge(empPosDict, requestBody);
    await this.employeePosDictRepository.save(empPosDict, { data: request });
    setLogDataDiff(request, { before, after: empPosDict });
    return new HttpSuccess(empPosDict.id);
  }

  /**
   * API ลบตำแหน่งลูกจ้างประจำ
   *
   * @summary ORG_ - ลบตำแหน่งลูกจ้างประจำ (ADMIN) #
   *
   * @param {string} id  Id ตำแหน่งลูกจ้างประจำ
   */
  @Delete("position/{id}")
  async delete(@Path() id: string, @Request() request: RequestWithUser) {
    // await new permission().PermissionDelete(request, "SYS_ORG_EMP");
    const delEmpPosDict = await this.employeePosDictRepository.findOne({ where: { id } });
    if (!delEmpPosDict) {
      throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูลตำแหน่งลูกจ้างประจำนี้");
    }
    await this.employeePosDictRepository.remove(delEmpPosDict, { data: request });
    return new HttpSuccess();
  }

  //   /**
  //    * API รายละเอียดข้อมูลตำแหน่งลูกจ้างประจำ
  //    *
  //    * @summary ORG_037 - รายละเอียดข้อมูลตำแหน่งลูกจ้างประจำ (ADMIN) #
  //    *
  //    */
  //   @Get("position/{id}")
  //   async GetEmpPositionById(@Path() id: string) {
  //     const empPosDict = await this.employeePosDictRepository.findOne({
  //       select: ["id", "posDictName", "posTypeId", "posLevelId"],
  //       where: { id: id },
  //     });
  //     if (!empPosDict) {
  //       throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูลกลุ่มงานนี้");
  //     }
  //     const empPosType = await this.employeePosTypeRepository.findOne({
  //       select: ["id", "posTypeName", "posTypeRank", "posTypeShortName"],
  //       where: { id: empPosDict.posTypeId },
  //     });
  //     if (!empPosType) {
  //       throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูลระดับชั้นงานนี้");
  //     }
  //     const empPosLevel = await this.employeePosLevelRepository.findOne({
  //       select: ["id", "posLevelName", "posLevelRank"],
  //       where: { id: empPosDict.posLevelId },
  //     });
  //     if (!empPosLevel) {
  //       throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูลตำแหน่งลูกจ้างประจำนี้");
  //     }

  //     const mapData = {
  //       id: empPosDict.id,
  //       posDictName: empPosDict.posDictName, //ชื่อตำแหน่ง
  //       posTypeId: empPosType.id,
  //       posTypeName: empPosType.posTypeName, //กลุ่มงาน
  //       posLeveId: empPosLevel.id,
  //       posLevelName: empPosLevel.posLevelName, //ระดับขั้นงาน
  //     };
  //     return new HttpSuccess(mapData);
  //   }

  /**
   * API รายละเอียดอัตรากำลังลูกจ้างประจำ
   *
   *
   */
  @Get("position/{id}")
  async detailPosition(@Path() id: string) {
    const posMaster = await this.employeePosMasterRepository.findOne({
      where: { id: id },
    });
    if (!posMaster) {
      throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูล");
    }
    const positions = await this.employeePositionRepository.find({
      where: { posMasterId: posMaster.id },
      relations: ["posType", "posLevel"],
      order: { lastUpdatedAt: "ASC" },
    });
    const formattedData = {
      id: posMaster.id,
      posMasterNoPrefix: posMaster.posMasterNoPrefix,
      posMasterNo: posMaster.posMasterNo,
      posMasterNoSuffix: posMaster.posMasterNoSuffix,
      reason: posMaster.reason,
      //   isOfficer: posMaster.isOfficer,
      isStaff: posMaster.isStaff,
      isDirector: posMaster.isDirector,
      positionSign: posMaster.positionSign,
      positions: positions.map((position) => ({
        id: position.id,
        positionName: position.positionName,
        posTypeId: position.posTypeId,
        posTypeName: position.posType == null ? null : position.posType.posTypeName,
        posTypeShortName: position.posType == null ? null : position.posType.posTypeShortName,
        posLevelId: position.posLevelId,
        posLevelName:
          position.posLevel == null || position.posType == null
            ? null
            : `${position.posType.posTypeShortName} ${position.posLevel.posLevelName}`,
        positionIsSelected: position.positionIsSelected,
      })),
    };
    return new HttpSuccess(formattedData);
  }

  /**
   * API ค้นหารายการตำแหน่งลูกจ้างประจำ
   *
   * @summary ORG_ - ค้นหารายการตำแหน่งลูกจ้างประจำ (ADMIN) #
   *
   */
  @Get("position")
  async GetEmpPosition(@Query("keyword") keyword?: string, @Query("type") type?: string) {
    let findData: any;
    switch (type) {
      case "positionName":
        findData = await this.employeePosDictRepository.find({
          where: { posDictName: Like(`%${keyword}%`) },
          relations: ["posType", "posLevel"],
          order: {
            posDictName: "ASC",
            createdAt: "DESC",
            posType: {
              posTypeRank: "ASC",
              createdAt: "DESC",
            },
            posLevel: {
              posLevelName: "ASC",
              createdAt: "DESC",
            },
          },
        });
        break;

      case "positionType":
        const findEmpTypes: EmployeePosType[] = await this.employeePosTypeRepository.find({
          where: { posTypeName: Like(`%${keyword}%`) },
          select: ["id"],
        });
        findData = await this.employeePosDictRepository.find({
          where: { posTypeId: In(findEmpTypes.map((x) => x.id)) },
          relations: ["posType", "posLevel"],
          order: {
            posDictName: "ASC",
            createdAt: "DESC",
            posType: {
              posTypeRank: "ASC",
              createdAt: "DESC",
            },
            posLevel: {
              posLevelName: "ASC",
              createdAt: "DESC",
            },
          },
        });
        break;

      case "positionLevel":
        // if (!isNaN(Number(keyword))) {
        //   console.log(">>>>>>>>", keyword);
        //   let findEmpLevels;
        //   if (Number(keyword) === 0) {
        //     findEmpLevels = await this.employeePosLevelRepository.find();
        //   } else {
        //     findEmpLevels = await this.employeePosLevelRepository.find({
        //       where: { posLevelName: Number(keyword) },
        //     });
        //   }
        //   findData = await this.employeePosDictRepository.find({
        //     where: { posLevelId: In(findEmpLevels.map((x) => x.id)) },
        //     relations: ["posType", "posLevel"],
        //     order: {
        //       posDictName: "ASC",
        //       createdAt: "DESC",
        //       posType: {
        //         posTypeRank: "ASC",
        //         createdAt: "DESC",
        //       },
        //       posLevel: {
        //         posLevelName: "ASC",
        //         createdAt: "DESC",
        //       },
        //     },
        //   });
        // } else {
        //   //กรณีเลือกค้นหาจาก"ระดับชั้นงาน" แต่กรอกไม่ใช่ number ให้ปล่อยมาหมดเลย
        //   findData = await this.employeePosDictRepository.find({
        //     relations: ["posType", "posLevel"],
        //     order: {
        //       posDictName: "ASC",
        //       createdAt: "DESC",
        //       posType: {
        //         posTypeRank: "ASC",
        //         createdAt: "DESC",
        //       },
        //       posLevel: {
        //         posLevelName: "ASC",
        //         createdAt: "DESC",
        //       },
        //     },
        //   });
        // }
        findData = await this.employeePosDictRepository
          .createQueryBuilder("posDict")
          .leftJoinAndSelect("posDict.posType", "posType")
          .leftJoinAndSelect("posDict.posLevel", "posLevel")
          .where(
            keyword
              ? "CONCAT(posType.posTypeShortName, ' ', posLevel.posLevelName) LIKE :keyword"
              : "1=1",
            { keyword: `%${keyword}%` },
          )
          .orderBy("posDict.posDictName", "ASC")
          .addOrderBy("posDict.createdAt", "DESC")
          .addOrderBy("posType.posTypeRank", "ASC")
          .addOrderBy("posType.createdAt", "DESC")
          .addOrderBy("posLevel.posLevelName", "ASC")
          .addOrderBy("posLevel.createdAt", "DESC")
          .getMany();
        break;

      default:
        findData = await this.employeePosDictRepository.find({
          relations: ["posType", "posLevel"],
          order: {
            posDictName: "ASC",
            createdAt: "DESC",
            posType: {
              posTypeRank: "ASC",
              createdAt: "DESC",
            },
            posLevel: {
              posLevelName: "ASC",
              createdAt: "DESC",
            },
          },
        });
        break;
    }
    const mapDataEmpPosDict = await Promise.all(
      findData.map(async (item: any) => {
        let posTypeName = null;
        let posLevelName = null;
        let posTypeShortName = null;

        if (item.posType !== null && item.posType !== undefined) {
          posTypeName = item.posType.posTypeName;
        }
        if (item.posLevel !== null && item.posLevel !== undefined) {
          posLevelName = item.posLevel.posLevelName;
        }
        if (item.posType !== null && item.posType !== undefined) {
          posTypeShortName = item.posType.posTypeShortName;
        }

        return {
          id: item.id,
          posDictName: item.posDictName,
          posTypeId: item.posTypeId,
          posTypeName: posTypeName,
          posTypeShortName: posTypeShortName,
          posLevelId: item.posLevelId,
          posLevelName: `${posTypeShortName} ${posLevelName}`,
          createdAt: item.createdAt,
          lastUpdatedAt: item.lastUpdatedAt,
          lastUpdateFullName: item.lastUpdateFullName,
        };
      }),
    );
    return new HttpSuccess(mapDataEmpPosDict);
  }

  /**
   * API เพิ่มอัตรากำลัง
   *
   * @summary ORG_ - เพิ่มอัตรากำลัง (ADMIN)
   *
   */
  @Post("master")
  async createEmpMaster(
    @Body()
    requestBody: CreateEmployeePosMaster,
    @Request() request: RequestWithUser,
  ) {
    await new permission().PermissionCreate(request, "SYS_ORG_EMP");
    const posMaster = Object.assign(new EmployeePosMaster(), requestBody);
    if (!posMaster) {
      throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูล");
    }

    let orgRoot: any = null;
    let SName: any = null;
    if (requestBody.orgRootId != null)
      orgRoot = await this.orgRootRepository.findOne({
        where: { id: requestBody.orgRootId },
      });
    if (!orgRoot) {
      let orgChild1: any = null;
      if (requestBody.orgChild1Id != null)
        orgChild1 = await this.child1Repository.findOne({
          where: { id: requestBody.orgChild1Id },
        });
      if (!orgChild1) {
        let orgChild2: any = null;
        if (requestBody.orgChild2Id != null)
          orgChild2 = await this.child2Repository.findOne({
            where: { id: requestBody.orgChild2Id },
          });
        if (!orgChild2) {
          let orgChild3: any = null;
          if (requestBody.orgChild3Id != null)
            orgChild3 = await this.child3Repository.findOne({
              where: { id: requestBody.orgChild3Id },
            });
          if (!orgChild3) {
            let orgChild4: any = null;
            if (requestBody.orgChild4Id != null)
              orgChild4 = await this.child4Repository.findOne({
                where: { id: requestBody.orgChild4Id },
              });
            if (!orgChild4) {
              throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูลโครงสร้าง");
            } else {
              const order: any = await this.employeePosMasterRepository.findOne({
                where: {
                  orgChild4Id: orgChild4.id,
                },
                order: { posMasterOrder: "DESC" },
              });
              posMaster.posMasterOrder =
                order !== null && order !== undefined && order.posMasterOrder
                  ? order.posMasterOrder + 1
                  : 1;
              posMaster.orgRootId = orgChild4.orgRootId;
              posMaster.orgChild1Id = orgChild4.orgChild1Id;
              posMaster.orgChild2Id = orgChild4.orgChild2Id;
              posMaster.orgChild3Id = orgChild4.orgChild3Id;
              posMaster.orgChild4Id = orgChild4.id;
              posMaster.orgRevisionId = orgChild4.orgRevisionId;
              SName = orgChild4.orgChild4ShortName;
            }
          } else {
            const order: any = await this.employeePosMasterRepository.findOne({
              where: {
                orgChild3Id: orgChild3.id,
                orgChild4Id: IsNull() || "",
              },
              order: { posMasterOrder: "DESC" },
            });
            posMaster.posMasterOrder =
              order !== null && order !== undefined && order.posMasterOrder
                ? order.posMasterOrder + 1
                : 1;
            posMaster.orgRootId = orgChild3.orgRootId;
            posMaster.orgChild1Id = orgChild3.orgChild1Id;
            posMaster.orgChild2Id = orgChild3.orgChild2Id;
            posMaster.orgChild3Id = orgChild3.id;
            posMaster.orgRevisionId = orgChild3.orgRevisionId;
            SName = orgChild3.orgChild3ShortName;
          }
        } else {
          const order: any = await this.employeePosMasterRepository.findOne({
            where: {
              orgChild2Id: orgChild2.id,
              orgChild3Id: IsNull() || "",
              orgChild4Id: IsNull() || "",
            },
            order: { posMasterOrder: "DESC" },
          });
          posMaster.posMasterOrder =
            order !== null && order !== undefined && order.posMasterOrder
              ? order.posMasterOrder + 1
              : 1;
          posMaster.orgRootId = orgChild2.orgRootId;
          posMaster.orgChild1Id = orgChild2.orgChild1Id;
          posMaster.orgChild2Id = orgChild2.id;
          posMaster.orgRevisionId = orgChild2.orgRevisionId;
          SName = orgChild2.orgChild2ShortName;
        }
      } else {
        const order: any = await this.employeePosMasterRepository.findOne({
          where: {
            orgChild1Id: orgChild1.id,
            orgChild2Id: IsNull() || "",
            orgChild3Id: IsNull() || "",
            orgChild4Id: IsNull() || "",
          },
          order: { posMasterOrder: "DESC" },
        });
        posMaster.posMasterOrder =
          order !== null && order !== undefined && order.posMasterOrder
            ? order.posMasterOrder + 1
            : 1;
        posMaster.orgRootId = orgChild1.orgRootId;
        posMaster.orgChild1Id = orgChild1.id;
        posMaster.orgRevisionId = orgChild1.orgRevisionId;
        SName = orgChild1.orgChild1ShortName;
      }
    } else {
      const order: any = await this.employeePosMasterRepository.findOne({
        where: {
          orgRootId: orgRoot.id,
          orgChild1Id: IsNull() || "",
          orgChild2Id: IsNull() || "",
          orgChild3Id: IsNull() || "",
          orgChild4Id: IsNull() || "",
        },
        order: { posMasterOrder: "DESC" },
      });
      posMaster.posMasterOrder =
        order !== null && order !== undefined && order.posMasterOrder
          ? order.posMasterOrder + 1
          : 1;
      posMaster.orgRootId = orgRoot.id;
      posMaster.orgRevisionId = orgRoot.orgRevisionId;
      SName = orgRoot.orgRootShortName;
    }

    const chk_SName0 = await this.employeePosMasterRepository.findOne({
      where: {
        orgRevisionId: posMaster.orgRevisionId,
        orgRoot: { orgRootShortName: SName /*id: requestBody.orgRootId ?? ""*/ },
        orgChild1Id: IsNull(),
        posMasterNo: requestBody.posMasterNo,
      },
      relations: ["orgRoot"],
    });
    if (chk_SName0 != null) {
      throw new HttpError(
        HttpStatusCode.INTERNAL_SERVER_ERROR,
        "ไม่สามารถใส่เลขที่ตำแหน่งซ้ำกันได้",
      );
    }

    const chk_SName1 = await this.employeePosMasterRepository.findOne({
      where: {
        orgRevisionId: posMaster.orgRevisionId,
        orgChild1: { orgChild1ShortName: SName /*id: requestBody.orgChild1Id ?? ""*/ },
        orgChild2Id: IsNull(),
        posMasterNo: requestBody.posMasterNo,
      },
      relations: ["orgChild1"],
    });
    if (chk_SName1 != null) {
      throw new HttpError(
        HttpStatusCode.INTERNAL_SERVER_ERROR,
        "ไม่สามารถใส่เลขที่ตำแหน่งซ้ำกันได้",
      );
    }

    const chk_SName2 = await this.employeePosMasterRepository.findOne({
      where: {
        orgRevisionId: posMaster.orgRevisionId,
        orgChild2: { orgChild2ShortName: SName /*id: requestBody.orgChild2Id ?? ""*/ },
        orgChild3Id: IsNull(),
        posMasterNo: requestBody.posMasterNo,
      },
      relations: ["orgChild2"],
    });
    if (chk_SName2 != null) {
      throw new HttpError(
        HttpStatusCode.INTERNAL_SERVER_ERROR,
        "ไม่สามารถใส่เลขที่ตำแหน่งซ้ำกันได้",
      );
    }

    const chk_SName3 = await this.employeePosMasterRepository.findOne({
      where: {
        orgRevisionId: posMaster.orgRevisionId,
        orgChild3: { orgChild3ShortName: SName /*id: requestBody.orgChild3Id ?? ""*/ },
        orgChild4Id: IsNull(),
        posMasterNo: requestBody.posMasterNo,
      },
      relations: ["orgChild3"],
    });
    if (chk_SName3 != null) {
      throw new HttpError(
        HttpStatusCode.INTERNAL_SERVER_ERROR,
        "ไม่สามารถใส่เลขที่ตำแหน่งซ้ำกันได้",
      );
    }

    const chk_SName4 = await this.employeePosMasterRepository.findOne({
      where: {
        orgRevisionId: posMaster.orgRevisionId,
        orgChild4: { orgChild4ShortName: SName /*id: requestBody.orgChild4Id ?? ""*/ },
        posMasterNo: requestBody.posMasterNo,
      },
      relations: ["orgChild4"],
    });
    if (chk_SName4 != null) {
      throw new HttpError(
        HttpStatusCode.INTERNAL_SERVER_ERROR,
        "ไม่สามารถใส่เลขที่ตำแหน่งซ้ำกันได้",
      );
    }
    const before = null;
    posMaster.createdUserId = request.user.sub;
    posMaster.createdFullName = request.user.name;
    posMaster.createdAt = new Date();
    posMaster.lastUpdateUserId = request.user.sub;
    posMaster.lastUpdateFullName = request.user.name;
    posMaster.lastUpdatedAt = new Date();
    await this.employeePosMasterRepository.save(posMaster, { data: request });

    const saved = await this.employeePosMasterRepository.save(posMaster, { data: request });
    saved.ancestorDNA = saved.id;
    await this.employeePosMasterRepository.save(saved, { data: request });

    setLogDataDiff(request, { before, after: posMaster });
    await Promise.all(
      requestBody.positions.map(async (x: any) => {
        const position = Object.assign(new EmployeePosition());
        position.positionName = x.posDictName;
        position.posTypeId = x.posTypeId == "" ? null : x.posTypeId;
        position.posLevelId = x.posLevelId == "" ? null : x.posLevelId;
        position.positionIsSelected = false;
        position.posMasterId = posMaster.id;
        position.createdUserId = request.user.sub;
        position.createdFullName = request.user.name;
        position.createdAt = new Date();
        position.lastUpdateUserId = request.user.sub;
        position.lastUpdateFullName = request.user.name;
        position.lastUpdatedAt = new Date();
        await this.employeePositionRepository.save(position, { data: request });
      }),
    );
    return new HttpSuccess(posMaster.id);
  }

  /**
   * API แก้ไขเลขที่ตำแหน่ง
   *
   * @summary ORG_ - แก้ไขเลขที่ตำแหน่ง (ADMIN)
   *
   */
  @Put("master/{id}")
  async updateEmpMaster(
    @Path() id: string,
    @Body()
    requestBody: CreateEmployeePosMaster,
    @Request() request: RequestWithUser,
  ) {
    await new permission().PermissionUpdate(request, "SYS_ORG_EMP");
    const posMaster = await this.employeePosMasterRepository.findOne({ where: { id: id } });
    if (!posMaster) {
      throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูลอัตรากำลัง");
    }
    let _null: any = null;
    posMaster.posMasterNo = requestBody.posMasterNo;
    posMaster.isDirector = requestBody.isDirector;
    // posMaster.isStaff = requestBody.isStaff == null?_null:requestBody.isStaff;
    // posMaster.positionSign = requestBody.positionSign == null ? _null : requestBody.positionSign;
    // posMaster.isOfficer = requestBody.isOfficer;
    posMaster.posMasterNoPrefix = requestBody.posMasterNoPrefix ?? _null;
    posMaster.posMasterNoSuffix = requestBody.posMasterNoSuffix ?? _null;
    posMaster.reason = requestBody.reason == null ? "" : requestBody.reason;
    posMaster.orgRootId = null;
    posMaster.orgChild1Id = null;
    posMaster.orgChild2Id = null;
    posMaster.orgChild3Id = null;
    posMaster.orgChild4Id = null;

    let orgRoot: any = null;
    let SName: any = null;
    if (requestBody.orgRootId != null)
      orgRoot = await this.orgRootRepository.findOne({
        where: { id: requestBody.orgRootId },
      });
    if (!orgRoot) {
      let orgChild1: any = null;
      if (requestBody.orgChild1Id != null)
        orgChild1 = await this.child1Repository.findOne({
          where: { id: requestBody.orgChild1Id },
        });
      if (!orgChild1) {
        let orgChild2: any = null;
        if (requestBody.orgChild2Id != null)
          orgChild2 = await this.child2Repository.findOne({
            where: { id: requestBody.orgChild2Id },
          });
        if (!orgChild2) {
          let orgChild3: any = null;
          if (requestBody.orgChild3Id != null)
            orgChild3 = await this.child3Repository.findOne({
              where: { id: requestBody.orgChild3Id },
            });
          if (!orgChild3) {
            let orgChild4: any = null;
            if (requestBody.orgChild4Id != null)
              orgChild4 = await this.child4Repository.findOne({
                where: { id: requestBody.orgChild4Id },
              });
            if (!orgChild4) {
              throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูลโครงสร้าง");
            } else {
              posMaster.orgRootId = orgChild4.orgRootId;
              posMaster.orgChild1Id = orgChild4.orgChild1Id;
              posMaster.orgChild2Id = orgChild4.orgChild2Id;
              posMaster.orgChild3Id = orgChild4.orgChild3Id;
              posMaster.orgChild4Id = orgChild4.id;
              posMaster.orgRevisionId = orgChild4.orgRevisionId;
              SName = orgChild4.orgChild4ShortName;
            }
          } else {
            posMaster.orgRootId = orgChild3.orgRootId;
            posMaster.orgChild1Id = orgChild3.orgChild1Id;
            posMaster.orgChild2Id = orgChild3.orgChild2Id;
            posMaster.orgChild3Id = orgChild3.id;
            posMaster.orgRevisionId = orgChild3.orgRevisionId;
            SName = orgChild3.orgChild3ShortName;
          }
        } else {
          posMaster.orgRootId = orgChild2.orgRootId;
          posMaster.orgChild1Id = orgChild2.orgChild1Id;
          posMaster.orgChild2Id = orgChild2.id;
          posMaster.orgRevisionId = orgChild2.orgRevisionId;
          SName = orgChild2.orgChild2ShortName;
        }
      } else {
        posMaster.orgRootId = orgChild1.orgRootId;
        posMaster.orgChild1Id = orgChild1.id;
        posMaster.orgRevisionId = orgChild1.orgRevisionId;
        SName = orgChild1.orgChild1ShortName;
      }
    } else {
      posMaster.orgRootId = orgRoot.id;
      posMaster.orgRevisionId = orgRoot.orgRevisionId;
      SName = orgRoot.orgRootShortName;
    }

    const chk_SName0 = await this.employeePosMasterRepository.findOne({
      where: {
        orgRevisionId: posMaster.orgRevisionId,
        orgRoot: { orgRootShortName: SName /*id: requestBody.orgRootId ?? ""*/ },
        orgChild1Id: IsNull(),
        posMasterNo: requestBody.posMasterNo,
        id: Not(posMaster.id),
      },
      relations: ["orgRoot"],
    });
    if (chk_SName0 != null) {
      throw new HttpError(
        HttpStatusCode.INTERNAL_SERVER_ERROR,
        "ไม่สามารถใส่เลขที่ตำแหน่งซ้ำกันได้",
      );
    }

    const chk_SName1 = await this.employeePosMasterRepository.findOne({
      where: {
        orgRevisionId: posMaster.orgRevisionId,
        orgChild1: { orgChild1ShortName: SName /*id: requestBody.orgChild1Id ?? ""*/ },
        orgChild2Id: IsNull(),
        posMasterNo: requestBody.posMasterNo,
        id: Not(posMaster.id),
      },
      relations: ["orgChild1"],
    });
    if (chk_SName1 != null) {
      throw new HttpError(
        HttpStatusCode.INTERNAL_SERVER_ERROR,
        "ไม่สามารถใส่เลขที่ตำแหน่งซ้ำกันได้",
      );
    }

    const chk_SName2 = await this.employeePosMasterRepository.findOne({
      where: {
        orgRevisionId: posMaster.orgRevisionId,
        orgChild2: { orgChild2ShortName: SName /*id: requestBody.orgChild2Id ?? ""*/ },
        orgChild3Id: IsNull(),
        posMasterNo: requestBody.posMasterNo,
        id: Not(posMaster.id),
      },
      relations: ["orgChild2"],
    });
    if (chk_SName2 != null) {
      throw new HttpError(
        HttpStatusCode.INTERNAL_SERVER_ERROR,
        "ไม่สามารถใส่เลขที่ตำแหน่งซ้ำกันได้",
      );
    }

    const chk_SName3 = await this.employeePosMasterRepository.findOne({
      where: {
        orgRevisionId: posMaster.orgRevisionId,
        orgChild3: { orgChild3ShortName: SName /*id: requestBody.orgChild3Id ?? ""*/ },
        orgChild4Id: IsNull(),
        posMasterNo: requestBody.posMasterNo,
        id: Not(posMaster.id),
      },
      relations: ["orgChild3"],
    });
    if (chk_SName3 != null) {
      throw new HttpError(
        HttpStatusCode.INTERNAL_SERVER_ERROR,
        "ไม่สามารถใส่เลขที่ตำแหน่งซ้ำกันได้",
      );
    }

    const chk_SName4 = await this.employeePosMasterRepository.findOne({
      where: {
        orgRevisionId: posMaster.orgRevisionId,
        orgChild4: { orgChild4ShortName: SName /*id: requestBody.orgChild4Id ?? ""*/ },
        posMasterNo: requestBody.posMasterNo,
        id: Not(posMaster.id),
      },
      relations: ["orgChild4"],
    });
    if (chk_SName4 != null) {
      throw new HttpError(
        HttpStatusCode.INTERNAL_SERVER_ERROR,
        "ไม่สามารถใส่เลขที่ตำแหน่งซ้ำกันได้",
      );
    }
    const before = structuredClone(posMaster);
    posMaster.createdUserId = request.user.sub; //สงสัยว่าทำให้ bug แก้ไขไม่ได้
    posMaster.createdFullName = request.user.name;
    posMaster.createdAt = new Date();
    posMaster.lastUpdateUserId = request.user.sub;
    posMaster.lastUpdateFullName = request.user.name;
    posMaster.lastUpdatedAt = new Date();
    await this.employeePosMasterRepository.save(posMaster, { data: request });
    setLogDataDiff(request, { before, after: posMaster });
    await this.employeePositionRepository.delete({ posMasterId: posMaster.id });

    await Promise.all(
      requestBody.positions.map(async (x: any) => {
        const position = Object.assign(new EmployeePosition());
        position.positionName = x.posDictName;
        position.posTypeId = x.posTypeId == "" ? null : x.posTypeId;
        position.posLevelId = x.posLevelId == "" ? null : x.posLevelId;
        position.positionIsSelected = false;
        position.posMasterId = posMaster.id;
        position.createdUserId = request.user.sub;
        position.createdFullName = request.user.name;
        position.createdAt = new Date();
        position.lastUpdateUserId = request.user.sub;
        position.lastUpdateFullName = request.user.name;
        position.lastUpdatedAt = new Date();
        await this.employeePositionRepository.save(position, { data: request });
      }),
    );

    if (posMaster.current_holderId != null) {
      const profile = await this.profileRepository.findOne({
        where: {
          id: posMaster.current_holderId,
        },
      });
      if (profile != null) {
        const positionNew = await this.employeePositionRepository.findOne({
          where: {
            // positionIsSelected: true,
            posMasterId: posMaster.id,
          },
        });
        if (positionNew != null) {
          profile.posLevelId = positionNew.posLevelId;
          profile.posTypeId = positionNew.posTypeId;
          profile.position = positionNew.positionName;
          profile.employeeOc = posMaster?.orgRoot?.orgRootName ?? null;
          profile.positionEmployeePositionId = positionNew.positionName;

          await this.profileRepository.save(profile);
        }
      }
    }
    return new HttpSuccess(posMaster.id);
  }

  /**
   * @summary แก้ไขตำแหน่งเงื่อนไข ลูกจ้างประจำ (ADMIN)
   */
  @Put("master/position-condition/{id}")
  async updatePositionCondition(
    @Path() id: string,
    @Body()
    requestBody: {
      isCondition: boolean | null;
      conditionReason: string | null;
    },
    @Request() request: RequestWithUser,
  ) {
    await new permission().PermissionUpdate(request, "SYS_POS_CONDITION");
    const posMaster = await this.employeePosMasterRepository.findOne({
      where: { id: id },
    });
    if (!posMaster) {
      throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูล");
    }

    Object.assign(posMaster, requestBody);
    posMaster.lastUpdateUserId = request.user.sub;
    posMaster.lastUpdateFullName = request.user.name;
    posMaster.lastUpdatedAt = new Date();
    await this.employeePosMasterRepository.save(posMaster);
    return new HttpSuccess();
  }

  /**
   * API รายละเอียดอัตรากำลัง
   *
   * @summary ORG_ - รายละเอียดอัตรากำลัง (ADMIN)
   *
   */
  //   @Get("position/{id}")
  //   async detailEmpPosition(@Path() id: string) {
  //     const posMaster = await this.employeePosMasterRepository.findOne({
  //       where: { id },
  //     });
  //     if (!posMaster) {
  //       throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูล");
  //     }
  //     const positions = await this.employeePositionRepository.find({
  //       where: { posMasterId: posMaster.id },
  //       relations: ["posType", "posLevel"],
  //       order: { lastUpdatedAt: "ASC" },
  //     });
  //     const formattedData = {
  //       id: posMaster.id,
  //       posMasterNoPrefix: posMaster.posMasterNoPrefix,
  //       posMasterNo: posMaster.posMasterNo,
  //       posMasterNoSuffix: posMaster.posMasterNoSuffix,
  //       positions: positions.map((position) => ({
  //         id: position.id,
  //         positionName: position.positionName,
  //         posTypeId: position.posTypeId,
  //         posTypeName: position.posType == null ? null : position.posType.posTypeName,
  //         posLevelId: position.posLevelId,
  //         posLevelName: position.posLevel == null ? null : position.posLevel.posLevelName,
  //         positionIsSelected: position.positionIsSelected,
  //       })),
  //     };
  //     return new HttpSuccess(formattedData);
  //   }

  /**
   * API ลบอัตรากำลัง
   *
   * @summary ORG_ - ลบอัตรากำลัง (ADMIN)
   *
   * @param {string} id  Id ตำแหน่ง
   */
  @Delete("master/{id}")
  async deleteEmpPosMaster(@Path() id: string, @Request() request: RequestWithUser) {
    await new permission().PermissionCreate(request, "SYS_ORG_EMP");
    const delPosMaster = await this.employeePosMasterRepository.findOne({
      where: { id },
    });
    if (!delPosMaster) {
      throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูลตำแหน่งในสายงานนี้");
    }
    await this.employeePositionRepository.delete({ posMasterId: id });
    await this.employeePosMasterRepository.delete({ id });
    return new HttpSuccess();
  }

  /**
   * API รายการอัตรากำลัง
   *
   * @summary ORG_ - รายการอัตรากำลัง (ADMIN)
   *
   */
  @Post("master/list")
  async listEmp(
    @Request() request: RequestWithUser,
    @Body()
    body: {
      id: string;
      revisionId: string;
      type: number;
      isAll: boolean;
      page: number;
      pageSize: number;
      keyword?: string;
    },
  ) {
    let typeCondition: any = {};
    let checkChildConditions: any = {};
    let keywordAsInt: any;
    let searchShortName = "1=1";
    let searchShortName0 = `CONCAT_WS(' ',orgRoot.orgRootShortName,NULLIF(posMaster.posMasterNoPrefix,''),posMaster.posMasterNo,NULLIF(posMaster.posMasterNoSuffix,''))`;
    let searchShortName1 = `CONCAT_WS(' ',orgChild1.orgChild1ShortName,NULLIF(posMaster.posMasterNoPrefix,''),posMaster.posMasterNo,NULLIF(posMaster.posMasterNoSuffix,''))`;
    let searchShortName2 = `CONCAT_WS(' ',orgChild2.orgChild2ShortName,NULLIF(posMaster.posMasterNoPrefix,''),posMaster.posMasterNo,NULLIF(posMaster.posMasterNoSuffix,''))`;
    let searchShortName3 = `CONCAT_WS(' ',orgChild3.orgChild3ShortName,NULLIF(posMaster.posMasterNoPrefix,''),posMaster.posMasterNo,NULLIF(posMaster.posMasterNoSuffix,''))`;
    let searchShortName4 = `CONCAT_WS(' ',orgChild4.orgChild4ShortName,NULLIF(posMaster.posMasterNoPrefix,''),posMaster.posMasterNo,NULLIF(posMaster.posMasterNoSuffix,''))`;
    let _data = await new permission().PermissionOrgList(request, "SYS_ORG_EMP");
    if (body.type === 0) {
      typeCondition = {
        orgRootId: body.id,
      };
      if (!body.isAll) {
        checkChildConditions = {
          orgChild1Id: IsNull(),
        };
        searchShortName = `CONCAT_WS(' ',orgRoot.orgRootShortName,NULLIF(posMaster.posMasterNoPrefix,''),posMaster.posMasterNo,NULLIF(posMaster.posMasterNoSuffix,'')) like '%${body.keyword}%'`;
      } else {
      }
    } else if (body.type === 1) {
      typeCondition = {
        orgChild1Id: body.id,
      };
      if (!body.isAll) {
        checkChildConditions = {
          orgChild2Id: IsNull(),
        };
        searchShortName = `CONCAT_WS(' ',orgChild1.orgChild1ShortName,NULLIF(posMaster.posMasterNoPrefix,''),posMaster.posMasterNo,NULLIF(posMaster.posMasterNoSuffix,'')) like '%${body.keyword}%'`;
      } else {
      }
    } else if (body.type === 2) {
      typeCondition = {
        orgChild2Id: body.id,
      };
      if (!body.isAll) {
        checkChildConditions = {
          orgChild3Id: IsNull(),
        };
        searchShortName = `CONCAT_WS(' ',orgChild2.orgChild2ShortName,NULLIF(posMaster.posMasterNoPrefix,''),posMaster.posMasterNo,NULLIF(posMaster.posMasterNoSuffix,'')) like '%${body.keyword}%'`;
      } else {
      }
    } else if (body.type === 3) {
      typeCondition = {
        orgChild3Id: body.id,
      };
      if (!body.isAll) {
        checkChildConditions = {
          orgChild4Id: IsNull(),
        };
        searchShortName = `CONCAT_WS(' ',orgChild3.orgChild3ShortName,NULLIF(posMaster.posMasterNoPrefix,''),posMaster.posMasterNo,NULLIF(posMaster.posMasterNoSuffix,'')) like '%${body.keyword}%'`;
      } else {
      }
    } else if (body.type === 4) {
      typeCondition = {
        orgChild4Id: body.id,
      };
      searchShortName = `CONCAT_WS(' ',orgChild4.orgChild4ShortName,NULLIF(posMaster.posMasterNoPrefix,''),posMaster.posMasterNo,NULLIF(posMaster.posMasterNoSuffix,'')) like '%${body.keyword}%'`;
    }
    let findPosition: any;
    let masterId = new Array();
    if (body.keyword != null && body.keyword != "") {
      const findTypes: EmployeePosType[] = await this.employeePosTypeRepository.find({
        where: { posTypeName: Like(`%${body.keyword}%`) },
        select: ["id"],
      });
      findPosition = await this.employeePositionRepository.find({
        where: { posTypeId: In(findTypes.map((x) => x.id)) },
        select: ["posMasterId"],
      });
      masterId = masterId.concat(findPosition.map((position: any) => position.posMasterId));
      //   const findLevel: EmployeePosLevel[] = await this.employeePosLevelRepository.find({
      //     where: { posLevelName: Like(`%${body.keyword}%`) },
      //     select: ["id"],
      //   });
      //   findPosition = await this.employeePositionRepository.find({
      //     where: { posLevelId: In(findLevel.map((x) => x.id)) },
      //     select: ["posMasterId"],
      //   });
      //   masterId = masterId.concat(findPosition.map((position: any) => position.posMasterId));
      findPosition = await this.employeePositionRepository.find({
        where: { positionName: Like(`%${body.keyword}%`) },
        select: ["posMasterId"],
      });
      masterId = masterId.concat(findPosition.map((position: any) => position.posMasterId));
      const numericMatch = body.keyword == null ? null : body.keyword.match(/\d+/);
      keywordAsInt = numericMatch ? parseInt(numericMatch[0], 10) : null;
      masterId = [...new Set(masterId)];
    }

    const revisionCondition = {
      orgRevisionId: body.revisionId,
    };
    const conditions = [
      {
        ...checkChildConditions,
        ...typeCondition,
        ...revisionCondition,
        ...(body.keyword &&
          (masterId.length > 0
            ? { id: In(masterId) }
            : /^\d+$/.test(body.keyword) ? { posMasterNo: keywordAsInt } : { posMasterNo: Like(`%${body.keyword}%`) })),
      },
    ];

    let query = AppDataSource.getRepository(EmployeePosMaster)
      .createQueryBuilder("posMaster")
      .leftJoinAndSelect("posMaster.orgRoot", "orgRoot")
      .leftJoinAndSelect("posMaster.orgChild1", "orgChild1")
      .leftJoinAndSelect("posMaster.orgChild2", "orgChild2")
      .leftJoinAndSelect("posMaster.orgChild3", "orgChild3")
      .leftJoinAndSelect("posMaster.orgChild4", "orgChild4")
      .leftJoinAndSelect("posMaster.current_holder", "current_holder")
      .leftJoinAndSelect("posMaster.next_holder", "next_holder")
      .leftJoinAndSelect("posMaster.orgRevision", "orgRevision")
      .leftJoinAndSelect("posMaster.positions", "positions")
      .leftJoinAndSelect("positions.posType", "posType")
      .leftJoinAndSelect("positions.posLevel", "posLevel")
      .where(conditions)
      .andWhere(
        _data.root != undefined && _data.root != null
          ? _data.root[0] != null
            ? `posMaster.orgRootId IN (:...root)`
            : `posMaster.orgRootId is null`
          : "1=1",
        {
          root: _data.root,
        },
      )
      .andWhere(
        _data.child1 != undefined && _data.child1 != null
          ? _data.child1[0] != null
            ? `posMaster.orgChild1Id IN (:...child1)`
            : // : `posMaster.orgChild1Id is ${_data.privilege == "PARENT" ? "not null" : "null"}`
              `posMaster.orgChild1Id is null`
          : "1=1",
        {
          child1: _data.child1,
        },
      )
      .andWhere(
        _data.child2 != undefined && _data.child2 != null
          ? _data.child2[0] != null
            ? `posMaster.orgChild2Id IN (:...child2)`
            : `posMaster.orgChild2Id is null`
          : "1=1",
        {
          child2: _data.child2,
        },
      )
      .andWhere(
        _data.child3 != undefined && _data.child3 != null
          ? _data.child3[0] != null
            ? `posMaster.orgChild3Id IN (:...child3)`
            : `posMaster.orgChild3Id is null`
          : "1=1",
        {
          child3: _data.child3,
        },
      )
      .andWhere(
        _data.child4 != undefined && _data.child4 != null
          ? _data.child4[0] != null
            ? `posMaster.orgChild4Id IN (:...child4)`
            : `posMaster.orgChild4Id is null`
          : "1=1",
        {
          child4: _data.child4,
        },
      );

    if (body.keyword != null && body.keyword != "") {
      query
        .orWhere(
          new Brackets((qb) => {
            qb.andWhere(
              body.keyword != null && body.keyword != ""
                ? body.isAll == false
                  ? searchShortName
                  : `CASE WHEN posMaster.orgChild1 is null THEN ${searchShortName0} WHEN posMaster.orgChild2 is null THEN ${searchShortName1} WHEN posMaster.orgChild3 is null THEN ${searchShortName2} WHEN posMaster.orgChild4 is null THEN ${searchShortName3} ELSE ${searchShortName4} END LIKE '%${body.keyword}%'`
                : "1=1",
            )
              .andWhere(checkChildConditions)
              .andWhere(typeCondition)
              .andWhere(revisionCondition);
          }),
        )
        .orWhere(
          new Brackets((qb) => {
            qb.andWhere(
              body.keyword != null && body.keyword != ""
                ? `CONCAT(current_holder.prefix, current_holder.firstName," ",current_holder.lastName)  like '%${body.keyword}%'`
                : "1=1",
              {
                keyword: `%${body.keyword}%`,
              },
            )
              .andWhere(checkChildConditions)
              .andWhere(typeCondition)
              .andWhere(revisionCondition);
          }),
        )
        .orWhere(
          new Brackets((qb) => {
            qb.andWhere(
              body.keyword != null && body.keyword != ""
                ? `CASE WHEN orgRevision.orgRevisionIsDraft = true THEN CONCAT(next_holder.prefix, next_holder.firstName,' ', next_holder.lastName) ELSE CONCAT(current_holder.prefix, current_holder.firstName,' ' , current_holder.lastName) END LIKE '%${body.keyword}%'`
                : "1=1",
              {
                keyword: `%${body.keyword}%`,
              },
            )
              .andWhere(checkChildConditions)
              .andWhere(typeCondition)
              .andWhere(revisionCondition);
          }),
        )
        .orWhere(
          new Brackets((qb) => {
            qb.andWhere(
              body.keyword != null && body.keyword != ""
                ? `CONCAT(posType.posTypeShortName,' ',posLevel.posLevelName) like '%${body.keyword}%'`
                : "1=1",
              {
                keyword: `%${body.keyword}%`,
              },
            )
              .andWhere(checkChildConditions)
              .andWhere(typeCondition)
              .andWhere(revisionCondition);
          }),
        );
    }

    let [posMaster, total] = await query
      .orderBy("orgRoot.orgRootOrder", "ASC")
      .addOrderBy("orgChild1.orgChild1Order", "ASC")
      .addOrderBy("orgChild2.orgChild2Order", "ASC")
      .addOrderBy("orgChild3.orgChild3Order", "ASC")
      .addOrderBy("orgChild4.orgChild4Order", "ASC")
      .addOrderBy("posMaster.posMasterOrder", "ASC")
      .skip((body.page - 1) * body.pageSize)
      .take(body.pageSize)
      .getManyAndCount();

    const formattedData = await Promise.all(
      posMaster.map(async (posMaster) => {
        const positions = await this.employeePositionRepository.find({
          where: {
            posMasterId: posMaster.id,
          },
          relations: ["posLevel", "posType"],
        });

        const authRoleName = await this.authRoleRepo.findOne({
          where: { id: String(posMaster.authRoleId) },
        });

        let profile: any;
        const chkRevision = await this.orgRevisionRepository.findOne({
          where: { id: posMaster.orgRevisionId },
        });
        if (chkRevision?.orgRevisionIsCurrent && !chkRevision?.orgRevisionIsDraft) {
          profile = await this.profileRepository.findOne({
            where: { id: String(posMaster.current_holderId) },
          });
        } else if (!chkRevision?.orgRevisionIsCurrent && chkRevision?.orgRevisionIsDraft) {
          profile = await this.profileRepository.findOne({
            where: { id: String(posMaster.next_holderId) },
          });
        }
        const type = await this.employeePosTypeRepository.findOne({
          where: { id: String(profile?.posTypeId) },
        });
        const level = await this.employeePosLevelRepository.findOne({
          where: { id: String(profile?.posLevelId) },
        });

        let shortName = "";

        if (
          posMaster.orgRootId !== null &&
          posMaster.orgChild1Id == null &&
          posMaster.orgChild2Id == null &&
          posMaster.orgChild3Id == null
        ) {
          body.type = 0;
          shortName = posMaster.orgRoot.orgRootShortName;
        } else if (
          posMaster.orgRootId !== null &&
          posMaster.orgChild1Id !== null &&
          posMaster.orgChild2Id == null &&
          posMaster.orgChild3Id == null
        ) {
          body.type = 1;
          shortName = posMaster.orgChild1.orgChild1ShortName;
        } else if (
          posMaster.orgRootId !== null &&
          posMaster.orgChild1Id !== null &&
          posMaster.orgChild2Id !== null &&
          posMaster.orgChild3Id == null
        ) {
          body.type = 2;
          shortName = posMaster.orgChild2.orgChild2ShortName;
        } else if (
          posMaster.orgRootId !== null &&
          posMaster.orgChild1Id !== null &&
          posMaster.orgChild2Id !== null &&
          posMaster.orgChild3Id !== null
        ) {
          body.type = 3;
          shortName = posMaster.orgChild3.orgChild3ShortName;
        } else if (
          posMaster.orgRootId !== null &&
          posMaster.orgChild1Id !== null &&
          posMaster.orgChild2Id !== null &&
          posMaster.orgChild3Id !== null
        ) {
          body.type = 4;
          shortName = posMaster.orgChild4.orgChild4ShortName;
        }

        return {
          id: posMaster.id,
          ancestorDNA: posMaster.ancestorDNA,
          current_holderId: posMaster.current_holderId,
          orgRootId: posMaster.orgRootId,
          orgChild1Id: posMaster.orgChild1Id,
          orgChild2Id: posMaster.orgChild2Id,
          orgChild3Id: posMaster.orgChild3Id,
          orgChild4Id: posMaster.orgChild4Id,
          posMasterNoPrefix: posMaster.posMasterNoPrefix ? posMaster.posMasterNoPrefix : null,
          posMasterNo: posMaster.posMasterNo ? posMaster.posMasterNo : null,
          posMasterNoSuffix: posMaster.posMasterNoSuffix ? posMaster.posMasterNoSuffix : null,
          reason: posMaster.reason,
          fullNameCurrentHolder:
            posMaster.current_holder == null
              ? null
              : `${posMaster.current_holder.prefix}${posMaster.current_holder.firstName} ${posMaster.current_holder.lastName}`,
          fullNameNextHolder:
            posMaster.next_holder == null
              ? null
              : `${posMaster.next_holder.prefix}${posMaster.next_holder.firstName} ${posMaster.next_holder.lastName}`,
          orgShortname: shortName,
          isSit: posMaster.isSit,
          profilePosition: profile == null ? null : profile.position,
          profilePostype: type == null ? null : type.posTypeName,
          profilePoslevel:
            level == null || type == null ? null : `${type.posTypeShortName} ${level.posLevelName}`,
          authRoleId: posMaster.authRoleId,
          isCondition: posMaster.isCondition,
          conditionReason: posMaster.conditionReason,
          authRoleName:
            authRoleName == null || authRoleName.roleName == null ? null : authRoleName.roleName,
          positions: positions.map((position) => ({
            id: position.id,
            positionName: position.positionName,
            posTypeId: position.posTypeId,
            posTypeName: position.posType == null ? null : position.posType.posTypeName,
            posTypeShortName: position.posType == null ? null : position.posType.posTypeShortName,
            posLevelId: position.posLevelId,
            posLevelName:
              position.posLevel == null || position.posType == null
                ? null
                : `${position.posType.posTypeShortName} ${position.posLevel.posLevelName}`,
            positionIsSelected: position.positionIsSelected,
          })),
        };
      }),
    );

    if (_data.privilege === "NORMAL" || _data.privilege === "CHILD") {
      //PARENT จะไม่มีทางเห็น ROOT , CHILD ยึดจาก CHILD ที่อยู่ลงไปข้างล่างและจะไม่เห็น CHILD ที่อยู่เหนือกว่า
      const nextChildMap: any = {
        //เอาไวเช็ค CHILD ถัดไป
        0: _data.child1,
        1: _data.child2,
        2: _data.child3,
        3: _data.child4,
      };
      const childValue = nextChildMap[body.type];
      if (_data.privilege === "NORMAL") {
        if (Array.isArray(childValue) && childValue.some((item) => item != null)) {
          return new HttpSuccess({ data: [], total: 0 });
        }
      } else if (_data.privilege === "CHILD") {
        const higherChildChecks = [
          { type: [0], child: _data.child1, next: _data.child2 },
          { type: [0, 1], child: _data.child2, next: _data.child3 },
          { type: [0, 1, 2], child: _data.child3, next: _data.child4 },
          { type: [0, 1, 2, 3], child: _data.child4, next: true },
        ];

        for (const check of higherChildChecks) {
          if (Array.isArray(check.child) && check.next == null) {
            if (check.type.includes(body.type)) {
              return new HttpSuccess({ data: [], total: 0 });
            }
          }
        }
      }
    }
    return new HttpSuccess({ data: formattedData, total });
  }

  /**
   * API จัดลำดับตำแหน่ง
   *
   * @summary ORG_ - จัดลำดับตำแหน่ง (ADMIN)
   *
   */
  @Post("sort")
  async SortEmp(
    @Body() requestBody: { id: string; type: number; sortId: string[] },
    @Request() request: RequestWithUser,
  ) {
    await new permission().PermissionUpdate(request, "SYS_ORG_EMP");
    switch (requestBody.type) {
      case 0: {
        const rootId = await this.employeePosMasterRepository.findOne({
          where: { orgRootId: requestBody.id },
        });
        if (!rootId?.id) {
          throw new HttpError(HttpStatusCode.NOT_FOUND, "not found rootId: " + requestBody.id);
        }
        const listPosMasterId_0 = await this.employeePosMasterRepository.find({
          where: {
            orgRootId: requestBody.id,
            orgChild1Id: IsNull(),
            orgChild2Id: IsNull(),
            orgChild3Id: IsNull(),
            orgChild4Id: IsNull(),
          },
          select: ["id", "posMasterOrder"],
        });
        if (!listPosMasterId_0) {
          throw new HttpError(HttpStatusCode.NOT_FOUND, "not found masterId type 0.");
        }
        const sortData_0 = listPosMasterId_0.map((data) => ({
          id: data.id,
          posMasterOrder: requestBody.sortId.indexOf(data.id) + 1,
        }));
        await this.employeePosMasterRepository.save(sortData_0);
        break;
      }

      case 1: {
        const child1Id = await this.employeePosMasterRepository.findOne({
          where: { orgChild1Id: requestBody.id },
        });
        if (!child1Id?.id) {
          throw new HttpError(HttpStatusCode.NOT_FOUND, "not found child1Id: " + requestBody.id);
        }
        const listPosMasterId_1 = await this.employeePosMasterRepository.find({
          where: {
            orgRootId: Not(IsNull()),
            orgChild1Id: requestBody.id,
            orgChild2Id: IsNull(),
            orgChild3Id: IsNull(),
            orgChild4Id: IsNull(),
          },
          select: ["id", "posMasterOrder"],
        });
        if (!listPosMasterId_1) {
          throw new HttpError(HttpStatusCode.NOT_FOUND, "not found masterId type 1.");
        }
        const sortData_1 = listPosMasterId_1.map((data) => ({
          id: data.id,
          posMasterOrder: requestBody.sortId.indexOf(data.id) + 1,
        }));
        await this.employeePosMasterRepository.save(sortData_1);
        break;
      }

      case 2: {
        const child2Id = await this.employeePosMasterRepository.findOne({
          where: { orgChild2Id: requestBody.id },
        });
        if (!child2Id?.id) {
          throw new HttpError(HttpStatusCode.NOT_FOUND, "not found child2Id: " + requestBody.id);
        }
        const listPosMasterId_2 = await this.employeePosMasterRepository.find({
          where: {
            orgRootId: Not(IsNull()),
            orgChild1Id: Not(IsNull()),
            orgChild2Id: requestBody.id,
            orgChild3Id: IsNull(),
            orgChild4Id: IsNull(),
          },
          select: ["id", "posMasterOrder"],
        });
        if (!listPosMasterId_2) {
          throw new HttpError(HttpStatusCode.NOT_FOUND, "not found masterId type 2.");
        }
        const sortData_2 = listPosMasterId_2.map((data) => ({
          id: data.id,
          posMasterOrder: requestBody.sortId.indexOf(data.id) + 1,
        }));
        await this.employeePosMasterRepository.save(sortData_2);
        break;
      }

      case 3: {
        const child3Id = await this.employeePosMasterRepository.findOne({
          where: { orgChild3Id: requestBody.id },
        });
        if (!child3Id?.id) {
          throw new HttpError(HttpStatusCode.NOT_FOUND, "not found chil3Id: " + requestBody.id);
        }
        const listPosMasterId_3 = await this.employeePosMasterRepository.find({
          where: {
            orgRootId: Not(IsNull()),
            orgChild1Id: Not(IsNull()),
            orgChild2Id: Not(IsNull()),
            orgChild3Id: requestBody.id,
            orgChild4Id: IsNull(),
          },
          select: ["id", "posMasterOrder"],
        });
        if (!listPosMasterId_3) {
          throw new HttpError(HttpStatusCode.NOT_FOUND, "not found masterId type 3.");
        }
        const sortData_3 = listPosMasterId_3.map((data) => ({
          id: data.id,
          posMasterOrder: requestBody.sortId.indexOf(data.id) + 1,
        }));
        await this.employeePosMasterRepository.save(sortData_3);
        break;
      }

      case 4: {
        const child4Id = await this.employeePosMasterRepository.findOne({
          where: { orgChild4Id: requestBody.id },
        });
        if (!child4Id?.id) {
          throw new HttpError(HttpStatusCode.NOT_FOUND, "not found child4Id: " + requestBody.id);
        }
        const listPosMasterId_4 = await this.employeePosMasterRepository.find({
          where: {
            orgRootId: Not(IsNull()),
            orgChild1Id: Not(IsNull()),
            orgChild2Id: Not(IsNull()),
            orgChild3Id: Not(IsNull()),
            orgChild4Id: requestBody.id,
          },
          select: ["id", "posMasterOrder"],
        });
        if (!listPosMasterId_4) {
          throw new HttpError(HttpStatusCode.NOT_FOUND, "not found masterId type 4.");
        }
        const sortData_4 = listPosMasterId_4.map((data) => ({
          id: data.id,
          posMasterOrder: requestBody.sortId.indexOf(data.id) + 1,
        }));
        await this.employeePosMasterRepository.save(sortData_4);
        break;
      }

      default:
        throw new HttpError(HttpStatusCode.NOT_FOUND, "not found type: " + requestBody.type);
    }
    return new HttpSuccess();
  }

  /**
   * API ดูประวัติอัตรากำลัง
   *
   * @summary ORG_ - ดูประวัติอัตรากำลัง (ADMIN)
   *
   * @param {string} id  Id อัตรากำลัง
   */
  @Get("history/{id}")
  async getEmpHistoryPosMater(@Path() id: string) {
    const posMaster = await this.employeePosMasterRepository.findOne({
      where: { id },
    });
    if (!posMaster) {
      throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูลตำแหน่งนี้");
    }
    const posMasters = await this.employeePosMasterRepository.find({
      where: {
        ancestorDNA:
          posMaster.ancestorDNA == null || posMaster.ancestorDNA == ""
            ? "123"
            : posMaster.ancestorDNA,
      },
      order: { lastUpdatedAt: "DESC" },
      relations: [
        "orgRoot",
        "orgChild1",
        "orgChild2",
        "orgChild3",
        "orgChild4",
        "current_holder",
        "positions",
        "positions.posLevel",
        "positions.posType",
      ],
    });
    const _data = posMasters.map((item) => ({
      id: item.id,
      orgShortName:
        item.orgRoot == null
          ? null
          : item.orgChild1 == null
            ? item.orgRoot.orgRootShortName
            : item.orgChild2 == null
              ? item.orgChild1.orgChild1ShortName
              : item.orgChild3 == null
                ? item.orgChild2.orgChild2ShortName
                : item.orgChild4 == null
                  ? item.orgChild3.orgChild3ShortName
                  : item.orgChild4.orgChild4ShortName,
      lastUpdatedAt: item.lastUpdatedAt ? item.lastUpdatedAt : null,
      posMasterNoPrefix: item.posMasterNoPrefix ? item.posMasterNoPrefix : null,
      posMasterNo: item.posMasterNo ? item.posMasterNo : null,
      posMasterNoSuffix: item.posMasterNoSuffix ? item.posMasterNoSuffix : null,
      reason: item.reason ? item.reason : null,
      position: item.positions.map((x) => x.positionName).join("/"),
      posLevel: item.positions.map((x) => x.posLevel.posLevelName).join("/"),
      posType: item.positions.map((x) => x.posType.posTypeName).join("/"),
      fullname:
        (item?.current_holder?.prefix ?? "") +
        "" +
        (item?.current_holder?.firstName ?? "") +
        " " +
        (item?.current_holder?.lastName ?? ""),
    }));
    return new HttpSuccess(_data);
  }

  /**
   * API ย้ายอัตรากำลัง
   *
   * @summary ORG_ - ย้ายอัตรากำลัง (ADMIN)
   *
   */
  @Post("move")
  async moveEmpPosMaster(
    @Body() requestBody: { id: string; type: number; positionMaster: string[] },
    @Request() request: RequestWithUser,
  ) {
    await new permission().PermissionUpdate(request, "SYS_ORG_EMP");
    const posMasters = await this.employeePosMasterRepository.find({
      where: { id: In(requestBody.positionMaster) },
    });

    const type0LastPosMasterNo =
      requestBody.type == 0
        ? await this.employeePosMasterRepository.find({
            where: {
              orgRootId: requestBody.id,
              orgChild1Id: IsNull(),
            },
          })
        : [];

    const type1LastPosMasterNo =
      requestBody.type == 1
        ? await this.employeePosMasterRepository.find({
            where: {
              orgChild1Id: requestBody.id,
              orgChild2Id: IsNull(),
            },
          })
        : [];

    const type2LastPosMasterNo =
      requestBody.type == 2
        ? await this.employeePosMasterRepository.find({
            where: {
              orgChild2Id: requestBody.id,
              orgChild3Id: IsNull(),
            },
          })
        : [];

    const type3LastPosMasterNo =
      requestBody.type == 3
        ? await this.employeePosMasterRepository.find({
            where: {
              orgChild3Id: requestBody.id,
              orgChild4Id: IsNull(),
            },
          })
        : [];

    const type4LastPosMasterNo =
      requestBody.type == 4
        ? await this.employeePosMasterRepository.find({
            where: {
              orgChild4Id: requestBody.id,
            },
          })
        : [];

    const allLastPosMasterNo = [
      ...type0LastPosMasterNo,
      ...type1LastPosMasterNo,
      ...type2LastPosMasterNo,
      ...type3LastPosMasterNo,
      ...type4LastPosMasterNo,
    ];

    // let maxPosMasterNo = Math.max(...allLastPosMasterNo.map((pos) => pos.posMasterNo), 0);

    let maxPosMasterOrder = Math.max(...allLastPosMasterNo.map((pos) => pos.posMasterOrder), 0);
    await Promise.all(
      posMasters.map(async (posMaster: any) => {
        let change = true;

        if (requestBody.type == 0) {
          const org = await this.orgRootRepository.findOne({
            where: { id: requestBody.id },
          });
          if (org != null) {
            const _posMaster = await this.employeePosMasterRepository.findOne({
              where: { orgRootId: org.id, posMasterNo: posMaster.posMasterNo },
            });
            if (_posMaster != null)
              throw new HttpError(
                HttpStatusCode.NOT_FOUND,
                `เลขที่ตำแหน่ง ${org.orgRootShortName} ${posMaster.posMasterNo} มีอยู่ในระบบอยู่แล้ว`,
              );
            if (
              posMaster.orgRootId == org.id &&
              posMaster.orgChild1Id == null &&
              posMaster.orgChild2Id == null &&
              posMaster.orgChild3Id == null &&
              posMaster.orgChild4Id == null
            )
              change = false;
            posMaster.orgRootId = org.id;
            posMaster.orgRevisionId = org.orgRevisionId;
            posMaster.orgChild1Id = null;
            posMaster.orgChild2Id = null;
            posMaster.orgChild3Id = null;
            posMaster.orgChild4Id = null;
          }
        }
        if (requestBody.type == 1) {
          const org = await this.child1Repository.findOne({
            where: { id: requestBody.id },
          });
          if (org != null) {
            const _posMaster = await this.employeePosMasterRepository.findOne({
              where: { orgChild1Id: org.id, posMasterNo: posMaster.posMasterNo },
            });
            if (_posMaster != null)
              throw new HttpError(
                HttpStatusCode.NOT_FOUND,
                `เลขที่ตำแหน่ง ${org.orgChild1ShortName} ${posMaster.posMasterNo} มีอยู่ในระบบอยู่แล้ว`,
              );
            if (
              posMaster.orgChild1Id == org.id &&
              posMaster.orgChild2Id == null &&
              posMaster.orgChild3Id == null &&
              posMaster.orgChild4Id == null
            )
              change = false;
            posMaster.orgRootId = org.orgRootId;
            posMaster.orgChild1Id = org.id;
            posMaster.orgRevisionId = org.orgRevisionId;
            posMaster.orgChild2Id = null;
            posMaster.orgChild3Id = null;
            posMaster.orgChild4Id = null;
          }
        }
        if (requestBody.type == 2) {
          const org = await this.child2Repository.findOne({
            where: { id: requestBody.id },
          });
          if (org != null) {
            const _posMaster = await this.employeePosMasterRepository.findOne({
              where: { orgChild2Id: org.id, posMasterNo: posMaster.posMasterNo },
            });
            if (_posMaster != null)
              throw new HttpError(
                HttpStatusCode.NOT_FOUND,
                `เลขที่ตำแหน่ง ${org.orgChild2ShortName} ${posMaster.posMasterNo} มีอยู่ในระบบอยู่แล้ว`,
              );
            if (
              posMaster.orgChild2Id == org.id &&
              posMaster.orgChild3Id == null &&
              posMaster.orgChild4Id == null
            )
              change = false;
            posMaster.orgRootId = org.orgRootId;
            posMaster.orgChild1Id = org.orgChild1Id;
            posMaster.orgChild2Id = org.id;
            posMaster.orgRevisionId = org.orgRevisionId;
            posMaster.orgChild3Id = null;
            posMaster.orgChild4Id = null;
          }
        }
        if (requestBody.type == 3) {
          const org = await this.child3Repository.findOne({
            where: { id: requestBody.id },
          });
          if (org != null) {
            const _posMaster = await this.employeePosMasterRepository.findOne({
              where: { orgChild3Id: org.id, posMasterNo: posMaster.posMasterNo },
            });
            if (_posMaster != null)
              throw new HttpError(
                HttpStatusCode.NOT_FOUND,
                `เลขที่ตำแหน่ง ${org.orgChild3ShortName} ${posMaster.posMasterNo} มีอยู่ในระบบอยู่แล้ว`,
              );
            if (posMaster.orgChild3Id == org.id && posMaster.orgChild4Id == null) change = false;
            posMaster.orgRootId = org.orgRootId;
            posMaster.orgChild1Id = org.orgChild1Id;
            posMaster.orgChild2Id = org.orgChild2Id;
            posMaster.orgChild3Id = org.id;
            posMaster.orgRevisionId = org.orgRevisionId;
            posMaster.orgChild4Id = null;
          }
        }
        if (requestBody.type == 4) {
          const org = await this.child4Repository.findOne({
            where: { id: requestBody.id },
          });
          if (org != null) {
            const _posMaster = await this.employeePosMasterRepository.findOne({
              where: { orgChild4Id: org.id, posMasterNo: posMaster.posMasterNo },
            });
            if (_posMaster != null)
              throw new HttpError(
                HttpStatusCode.NOT_FOUND,
                `เลขที่ตำแหน่ง ${org.orgChild4ShortName} ${posMaster.posMasterNo} มีอยู่ในระบบอยู่แล้ว`,
              );
            if (posMaster.orgChild4Id == org.id) change = false;
            posMaster.orgRootId = org.orgRootId;
            posMaster.orgChild1Id = org.orgChild1Id;
            posMaster.orgChild2Id = org.orgChild2Id;
            posMaster.orgChild3Id = org.orgChild3Id;
            posMaster.orgChild4Id = org.id;
            posMaster.orgRevisionId = org.orgRevisionId;
          }
        }
        if (change == true) {
          posMaster.posMasterOrder = maxPosMasterOrder += 1;
          posMaster.createdUserId = request.user.sub;
          posMaster.createdFullName = request.user.name;
          posMaster.createdAt = new Date();
          posMaster.lastUpdateUserId = request.user.sub;
          posMaster.lastUpdateFullName = request.user.name;
          posMaster.lastUpdatedAt = new Date();
          await this.employeePosMasterRepository.save(posMaster);
        }
      }),
    );
    return new HttpSuccess();
  }

  /**
   * API ตำแหน่งทั้งหมด
   *
   * @summary ORG_ - ตำแหน่งทั้งหมด (ADMIN)
   *
   */
  @Post("summary")
  async PositionEmpSummary(@Body() requestBody: { id: string; type: number; isNode: boolean }) {
    let summary: any;
    let totalPosition: any;
    let totalPositionCurrentUse: any;
    let totalPositionCurrentVacant: any;
    let totalPositionNextUse: any;
    let totalPositionNextVacant: any;

    if (requestBody.isNode === true) {
      switch (requestBody.type) {
        case 0: {
          totalPosition = await this.employeePosMasterRepository.count({
            where: { orgRootId: requestBody.id },
          });
          totalPositionCurrentUse = await this.employeePosMasterRepository.count({
            where: {
              orgRootId: requestBody.id,
              current_holderId: Not(IsNull()) || Not(""),
            },
          });
          totalPositionCurrentVacant = await this.employeePosMasterRepository.count({
            where: {
              orgRootId: requestBody.id,
              current_holderId: IsNull() || "",
            },
          });
          totalPositionNextUse = await this.employeePosMasterRepository.count({
            where: {
              orgRootId: requestBody.id,
              next_holderId: Not(IsNull()) || Not(""),
            },
          });
          totalPositionNextVacant = await this.employeePosMasterRepository.count({
            where: {
              orgRootId: requestBody.id,
              next_holderId: IsNull() || "",
            },
          });
          break;
        }
        case 1: {
          totalPosition = await this.employeePosMasterRepository.count({
            where: { orgChild1Id: requestBody.id },
          });
          totalPositionCurrentUse = await this.employeePosMasterRepository.count({
            where: {
              orgChild1Id: requestBody.id,
              current_holderId: Not(IsNull()) || Not(""),
            },
          });
          totalPositionCurrentVacant = await this.employeePosMasterRepository.count({
            where: {
              orgChild1Id: requestBody.id,
              current_holderId: IsNull() || "",
            },
          });
          totalPositionNextUse = await this.employeePosMasterRepository.count({
            where: {
              orgChild1Id: requestBody.id,
              next_holderId: Not(IsNull()) || Not(""),
            },
          });
          totalPositionNextVacant = await this.employeePosMasterRepository.count({
            where: {
              orgChild1Id: requestBody.id,
              next_holderId: IsNull() || "",
            },
          });
          break;
        }
        case 2: {
          totalPosition = await this.employeePosMasterRepository.count({
            where: { orgChild2Id: requestBody.id },
          });
          totalPositionCurrentUse = await this.employeePosMasterRepository.count({
            where: {
              orgChild2Id: requestBody.id,
              current_holderId: Not(IsNull()) || Not(""),
            },
          });
          totalPositionCurrentVacant = await this.employeePosMasterRepository.count({
            where: {
              orgChild2Id: requestBody.id,
              current_holderId: IsNull() || "",
            },
          });
          totalPositionNextUse = await this.employeePosMasterRepository.count({
            where: {
              orgChild2Id: requestBody.id,
              next_holderId: Not(IsNull()) || Not(""),
            },
          });
          totalPositionNextVacant = await this.employeePosMasterRepository.count({
            where: {
              orgChild2Id: requestBody.id,
              next_holderId: IsNull() || "",
            },
          });
          break;
        }
        case 3: {
          totalPosition = await this.employeePosMasterRepository.count({
            where: { orgChild3Id: requestBody.id },
          });
          totalPositionCurrentUse = await this.employeePosMasterRepository.count({
            where: {
              orgChild3Id: requestBody.id,
              current_holderId: Not(IsNull()) || Not(""),
            },
          });
          totalPositionCurrentVacant = await this.employeePosMasterRepository.count({
            where: {
              orgChild3Id: requestBody.id,
              current_holderId: IsNull() || "",
            },
          });
          totalPositionNextUse = await this.employeePosMasterRepository.count({
            where: {
              orgChild3Id: requestBody.id,
              next_holderId: Not(IsNull()) || Not(""),
            },
          });
          totalPositionNextVacant = await this.employeePosMasterRepository.count({
            where: {
              orgChild3Id: requestBody.id,
              next_holderId: IsNull() || "",
            },
          });
          break;
        }
        case 4: {
          totalPosition = await this.employeePosMasterRepository.count({
            where: { orgChild4Id: requestBody.id },
          });
          totalPositionCurrentUse = await this.employeePosMasterRepository.count({
            where: {
              orgChild4Id: requestBody.id,
              current_holderId: Not(IsNull()) || Not(""),
            },
          });
          totalPositionCurrentVacant = await this.employeePosMasterRepository.count({
            where: {
              orgChild4Id: requestBody.id,
              current_holderId: IsNull() || "",
            },
          });
          totalPositionNextUse = await this.employeePosMasterRepository.count({
            where: {
              orgChild4Id: requestBody.id,
              next_holderId: Not(IsNull()) || Not(""),
            },
          });
          totalPositionNextVacant = await this.employeePosMasterRepository.count({
            where: {
              orgChild4Id: requestBody.id,
              next_holderId: IsNull() || "",
            },
          });
          break;
        }
        default:
          break;
      }
    } else {
      switch (requestBody.type) {
        case 0: {
          totalPosition = await this.employeePosMasterRepository.count({
            where: {
              orgRootId: requestBody.id,
              orgChild1Id: IsNull() || "",
              orgChild2Id: IsNull() || "",
              orgChild3Id: IsNull() || "",
              orgChild4Id: IsNull() || "",
            },
          });
          totalPositionCurrentUse = await this.employeePosMasterRepository.count({
            where: {
              orgRootId: requestBody.id,
              orgChild1Id: IsNull() || "",
              orgChild2Id: IsNull() || "",
              orgChild3Id: IsNull() || "",
              orgChild4Id: IsNull() || "",
              current_holderId: Not(IsNull()) || Not(""),
            },
          });
          totalPositionCurrentVacant = await this.employeePosMasterRepository.count({
            where: {
              orgRootId: requestBody.id,
              orgChild1Id: IsNull() || "",
              orgChild2Id: IsNull() || "",
              orgChild3Id: IsNull() || "",
              orgChild4Id: IsNull() || "",
              current_holderId: IsNull() || "",
            },
          });
          totalPositionNextUse = await this.employeePosMasterRepository.count({
            where: {
              orgRootId: requestBody.id,
              orgChild1Id: IsNull() || "",
              orgChild2Id: IsNull() || "",
              orgChild3Id: IsNull() || "",
              orgChild4Id: IsNull() || "",
              next_holderId: Not(IsNull()) || Not(""),
            },
          });
          totalPositionNextVacant = await this.employeePosMasterRepository.count({
            where: {
              orgRootId: requestBody.id,
              orgChild1Id: IsNull() || "",
              orgChild2Id: IsNull() || "",
              orgChild3Id: IsNull() || "",
              orgChild4Id: IsNull() || "",
              next_holderId: IsNull() || "",
            },
          });
          break;
        }
        case 1: {
          totalPosition = await this.employeePosMasterRepository.count({
            where: {
              orgRootId: Not(IsNull()) || Not(""),
              orgChild1Id: requestBody.id,
              orgChild2Id: IsNull() || "",
              orgChild3Id: IsNull() || "",
              orgChild4Id: IsNull() || "",
            },
          });
          totalPositionCurrentUse = await this.employeePosMasterRepository.count({
            where: {
              orgRootId: Not(IsNull()) || Not(""),
              orgChild1Id: requestBody.id,
              orgChild2Id: IsNull() || "",
              orgChild3Id: IsNull() || "",
              orgChild4Id: IsNull() || "",
              current_holderId: Not(IsNull()) || Not(""),
            },
          });
          totalPositionCurrentVacant = await this.employeePosMasterRepository.count({
            where: {
              orgRootId: Not(IsNull()) || Not(""),
              orgChild1Id: requestBody.id,
              orgChild2Id: IsNull() || "",
              orgChild3Id: IsNull() || "",
              orgChild4Id: IsNull() || "",
              current_holderId: IsNull() || "",
            },
          });
          totalPositionNextUse = await this.employeePosMasterRepository.count({
            where: {
              orgRootId: Not(IsNull()) || Not(""),
              orgChild1Id: requestBody.id,
              orgChild2Id: IsNull() || "",
              orgChild3Id: IsNull() || "",
              orgChild4Id: IsNull() || "",
              next_holderId: Not(IsNull()) || Not(""),
            },
          });
          totalPositionNextVacant = await this.employeePosMasterRepository.count({
            where: {
              orgRootId: Not(IsNull()) || Not(""),
              orgChild1Id: requestBody.id,
              orgChild2Id: IsNull() || "",
              orgChild3Id: IsNull() || "",
              orgChild4Id: IsNull() || "",
              next_holderId: IsNull() || "",
            },
          });
          break;
        }
        case 2: {
          totalPosition = await this.employeePosMasterRepository.count({
            where: {
              orgRootId: Not(IsNull()) || Not(""),
              orgChild1Id: Not(IsNull()) || Not(""),
              orgChild2Id: requestBody.id,
              orgChild3Id: IsNull() || "",
              orgChild4Id: IsNull() || "",
            },
          });
          totalPositionCurrentUse = await this.employeePosMasterRepository.count({
            where: {
              orgRootId: Not(IsNull()) || Not(""),
              orgChild1Id: Not(IsNull()) || Not(""),
              orgChild2Id: requestBody.id,
              orgChild3Id: IsNull() || "",
              orgChild4Id: IsNull() || "",
              current_holderId: Not(IsNull()) || Not(""),
            },
          });
          totalPositionCurrentVacant = await this.employeePosMasterRepository.count({
            where: {
              orgRootId: Not(IsNull()) || Not(""),
              orgChild1Id: Not(IsNull()) || Not(""),
              orgChild2Id: requestBody.id,
              orgChild3Id: IsNull() || "",
              orgChild4Id: IsNull() || "",
              current_holderId: IsNull() || "",
            },
          });
          totalPositionNextUse = await this.employeePosMasterRepository.count({
            where: {
              orgRootId: Not(IsNull()) || Not(""),
              orgChild1Id: Not(IsNull()) || Not(""),
              orgChild2Id: requestBody.id,
              orgChild3Id: IsNull() || "",
              orgChild4Id: IsNull() || "",
              next_holderId: Not(IsNull()) || Not(""),
            },
          });
          totalPositionNextVacant = await this.employeePosMasterRepository.count({
            where: {
              orgRootId: Not(IsNull()) || Not(""),
              orgChild1Id: Not(IsNull()) || Not(""),
              orgChild2Id: requestBody.id,
              orgChild3Id: IsNull() || "",
              orgChild4Id: IsNull() || "",
              next_holderId: IsNull() || "",
            },
          });
          break;
        }
        case 3: {
          totalPosition = await this.employeePosMasterRepository.count({
            where: {
              orgRootId: Not(IsNull()) || Not(""),
              orgChild1Id: Not(IsNull()) || Not(""),
              orgChild2Id: Not(IsNull()) || Not(""),
              orgChild3Id: requestBody.id,
              orgChild4Id: IsNull() || "",
            },
          });
          totalPositionCurrentUse = await this.employeePosMasterRepository.count({
            where: {
              orgRootId: Not(IsNull()) || Not(""),
              orgChild1Id: Not(IsNull()) || Not(""),
              orgChild2Id: Not(IsNull()) || Not(""),
              orgChild3Id: requestBody.id,
              orgChild4Id: IsNull() || "",
              current_holderId: Not(IsNull()) || Not(""),
            },
          });
          totalPositionCurrentVacant = await this.employeePosMasterRepository.count({
            where: {
              orgRootId: Not(IsNull()) || Not(""),
              orgChild1Id: Not(IsNull()) || Not(""),
              orgChild2Id: Not(IsNull()) || Not(""),
              orgChild3Id: requestBody.id,
              orgChild4Id: IsNull() || "",
              current_holderId: IsNull() || "",
            },
          });
          totalPositionNextUse = await this.employeePosMasterRepository.count({
            where: {
              orgRootId: Not(IsNull()) || Not(""),
              orgChild1Id: Not(IsNull()) || Not(""),
              orgChild2Id: Not(IsNull()) || Not(""),
              orgChild3Id: requestBody.id,
              orgChild4Id: IsNull() || "",
              next_holderId: Not(IsNull()) || Not(""),
            },
          });
          totalPositionNextVacant = await this.employeePosMasterRepository.count({
            where: {
              orgRootId: Not(IsNull()) || Not(""),
              orgChild1Id: Not(IsNull()) || Not(""),
              orgChild2Id: Not(IsNull()) || Not(""),
              orgChild3Id: requestBody.id,
              orgChild4Id: IsNull() || "",
              next_holderId: IsNull() || "",
            },
          });
          break;
        }
        case 4: {
          totalPosition = await this.employeePosMasterRepository.count({
            where: {
              orgRootId: Not(IsNull()) || Not(""),
              orgChild1Id: Not(IsNull()) || Not(""),
              orgChild2Id: Not(IsNull()) || Not(""),
              orgChild3Id: Not(IsNull()) || Not(""),
              orgChild4Id: requestBody.id,
            },
          });
          totalPositionCurrentUse = await this.employeePosMasterRepository.count({
            where: {
              orgRootId: Not(IsNull()) || Not(""),
              orgChild1Id: Not(IsNull()) || Not(""),
              orgChild2Id: Not(IsNull()) || Not(""),
              orgChild3Id: Not(IsNull()) || Not(""),
              orgChild4Id: requestBody.id,
              current_holderId: Not(IsNull()) || Not(""),
            },
          });
          totalPositionCurrentVacant = await this.employeePosMasterRepository.count({
            where: {
              orgRootId: Not(IsNull()) || Not(""),
              orgChild1Id: Not(IsNull()) || Not(""),
              orgChild2Id: Not(IsNull()) || Not(""),
              orgChild3Id: Not(IsNull()) || Not(""),
              orgChild4Id: requestBody.id,
              current_holderId: IsNull() || "",
            },
          });
          totalPositionNextUse = await this.employeePosMasterRepository.count({
            where: {
              orgRootId: Not(IsNull()) || Not(""),
              orgChild1Id: Not(IsNull()) || Not(""),
              orgChild2Id: Not(IsNull()) || Not(""),
              orgChild3Id: Not(IsNull()) || Not(""),
              orgChild4Id: requestBody.id,
              next_holderId: Not(IsNull()) || Not(""),
            },
          });
          totalPositionNextVacant = await this.employeePosMasterRepository.count({
            where: {
              orgRootId: Not(IsNull()) || Not(""),
              orgChild1Id: Not(IsNull()) || Not(""),
              orgChild2Id: Not(IsNull()) || Not(""),
              orgChild3Id: Not(IsNull()) || Not(""),
              orgChild4Id: requestBody.id,
              next_holderId: IsNull() || "",
            },
          });
          break;
        }
        default:
          break;
      }
    }

    summary = {
      totalPosition: totalPosition,
      totalPositionCurrentUse: totalPositionCurrentUse,
      totalPositionCurrentVacant: totalPositionCurrentVacant,
      totalPositionNextUse: totalPositionNextUse,
      totalPositionNextVacant: totalPositionNextVacant,
    };
    return new HttpSuccess(summary);
  }
  /**
   * API สร้างคนครองตำแหน่ง
   *
   * @summary ORG_ - สร้างคนครองตำแหน่ง (ADMIN)
   *
   */
  @Post("profile")
  async createEmpHolder(
    @Body() requestBody: { posMaster: string; position: string; profileId: string; isSit: boolean },
    @Request() request: RequestWithUser,
  ) {
    await new permission().PermissionCreate(request, "SYS_ORG_EMP");
    const dataMaster = await this.employeePosMasterRepository.findOne({
      where: { id: requestBody.posMaster },
      relations: ["positions"],
    });
    if (!dataMaster) {
      throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูลตำแหน่งนี้");
    }
    dataMaster.positions.forEach(async (position) => {
      if (position.id === requestBody.position) {
        position.positionIsSelected = true;
        const profile = await this.profileRepository.findOne({
          where: { id: requestBody.profileId },
        });
        if (profile != null) {
          const _null: any = null;
          profile.posLevelId = position?.posLevelId ?? _null;
          profile.posTypeId = position?.posTypeId ?? _null;
          profile.position = position?.positionName ?? _null;
          await this.profileRepository.save(profile);
        }
      } else {
        position.positionIsSelected = false;
      }
      await this.employeePositionRepository.save(position);
    });

    dataMaster.isSit = requestBody.isSit;
    dataMaster.current_holderId = requestBody.profileId;
    dataMaster.lastUpdatedAt = new Date();
    // dataMaster.next_holderId = requestBody.profileId;
    await this.employeePosMasterRepository.save(dataMaster);
    await CreatePosMasterHistoryEmployee(dataMaster.id, request);

    return new HttpSuccess();
  }

  /**
   * API ลบคนครองตำแหน่ง
   *
   * @summary ORG_ - ลบคนครองตำแหน่ง (ADMIN)
   *
   * @param  {string} id  *Id posMaster
   */
  @Post("profile/delete/{id}")
  async deleteEmpHolder(@Path() id: string, @Request() request: RequestWithUser) {
    await new permission().PermissionUpdate(request, "SYS_ORG_EMP");
    const dataMaster = await this.employeePosMasterRepository.findOne({
      where: { id: id },
      relations: ["positions", "orgRevision"],
    });
    if (!dataMaster) {
      throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูลตำแหน่งนี้");
    }
    // if (dataMaster.current_holderId != null) {
    //   const profile = await this.profileRepository.findOne({
    //     where: {
    //       id: dataMaster.current_holderId,
    //     },
    //   });
    //   const _null: any = null;
    //   if (profile != null) {
    //     profile.posLevelId = _null;
    //     profile.posTypeId = _null;
    //     profile.position = _null;
    //     profile.employeeOc = _null;
    //     profile.positionEmployeePositionId = _null;
    //     await this.profileRepository.save(profile);
    //   }
    // }
    if (dataMaster.current_holderId) {
      await this.keycloakAttributeService.clearOrgDnaAttributes(
        [dataMaster.current_holderId],
        "PROFILE_EMPLOYEE",
      );
    }

    await this.employeePosMasterRepository.update(id, {
      isSit: false,
      next_holderId: null,
      current_holderId: null,
    });

    dataMaster.positions.forEach(async (position) => {
      await this.employeePositionRepository.update(position.id, {
        positionIsSelected: false,
      });
    });
    if (dataMaster.orgRevision.orgRevisionIsCurrent) {
      await CreatePosMasterHistoryEmployee(dataMaster.id, request);
    }
    return new HttpSuccess();
  }

  /**
   * API สืบทอดตำแหน่ง
   *
   * @summary ORG_ - สืบทอดตำแหน่ง (ADMIN)
   *
   */
  @Post("dna")
  async dnaEmp(
    @Body() requestBody: { draftPositionId: string; publishPositionId: string },
    @Request() request: RequestWithUser,
  ) {
    await new permission().PermissionUpdate(request, "SYS_ORG_EMP");
    const findDraft = await this.orgRevisionRepository.findOne({
      where: {
        orgRevisionIsDraft: true,
      },
    });
    if (!findDraft) {
      throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูลโครงสร้างที่เผยแพร่");
    }

    const dataPublish = await this.employeePosMasterRepository.findOne({
      where: {
        id: requestBody.publishPositionId,
      },
    });
    if (!dataPublish) {
      throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูลตำแหน่งนี้");
    }

    const dataDraft = await this.employeePosMasterRepository.findOne({
      where: {
        id: requestBody.draftPositionId,
      },
    });
    if (!dataDraft) {
      throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูลตำแหน่งนี้");
    }

    await this.employeePosMasterRepository.update(
      { orgRevisionId: findDraft.id, ancestorDNA: dataPublish.ancestorDNA },
      { ancestorDNA: "" },
    );
    if (dataPublish.ancestorDNA == null || dataPublish.ancestorDNA == "")
      dataPublish.ancestorDNA = dataPublish.id;
    dataDraft.ancestorDNA = dataPublish.ancestorDNA;
    await this.employeePosMasterRepository.save(dataDraft);
    await this.employeePosMasterRepository.save(dataPublish);

    return new HttpSuccess();
  }

  /**
   * API บันทึกตำแหน่งใหม่
   *
   * @summary บันทึกตำแหน่งใหม่
   *
   */
  @Post("report/current")
  async reportApproveCurrent(
    @Body()
    body: {
      posmasterId: string;
      positionId: string;
      profileId: string;
    },
    @Request() request: RequestWithUser,
  ) {
    await new permission().PermissionCreate(request, "SYS_ORG_EMP");
    const posMaster = await this.employeePosMasterRepository.findOne({
      where: { id: body.posmasterId },
      relations: ["orgRoot"],
    });
    if (posMaster == null) throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูลตำแหน่งนี้");

    const posMasterOld = await this.employeePosMasterRepository.findOne({
      where: {
        current_holderId: body.profileId,
        orgRevisionId: posMaster.orgRevisionId,
      },
    });
    if (posMasterOld != null) {
      posMasterOld.current_holderId = null;
      posMasterOld.lastUpdatedAt = new Date();
    }
    // if (posMasterOld != null) posMasterOld.next_holderId = null;

    const positionOld = await this.employeePositionRepository.findOne({
      where: {
        posMasterId: posMasterOld?.id,
        positionIsSelected: true,
      },
    });
    if (positionOld != null) {
      positionOld.positionIsSelected = false;
      await this.employeePositionRepository.save(positionOld);
    }

    const checkPosition = await this.employeePositionRepository.find({
      where: {
        posMasterId: body.posmasterId,
        positionIsSelected: true,
      },
    });
    if (checkPosition.length > 0) {
      const clearPosition = checkPosition.map((positions) => ({
        ...positions,
        positionIsSelected: false,
      }));
      await this.employeePositionRepository.save(clearPosition);
    }

    const profile = await this.profileRepository.findOne({
      where: { id: body.profileId },
    });
    if (profile == null)
      throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูลทะเบียนประวัตินี้");

    posMaster.current_holderId = body.profileId;
    posMaster.lastUpdatedAt = new Date();
    // posMaster.next_holderId = body.profileId;
    if (posMasterOld != null) {
      await this.employeePosMasterRepository.save(posMasterOld);
      await CreatePosMasterHistoryEmployee(posMasterOld.id, request);
    }
    await this.employeePosMasterRepository.save(posMaster);

    const positionNew = await this.employeePositionRepository.findOne({
      where: {
        id: body.positionId,
        posMasterId: body.posmasterId,
      },
    });
    if (positionNew != null) {
      positionNew.positionIsSelected = true;
      profile.posLevelId = positionNew.posLevelId;
      profile.posTypeId = positionNew.posTypeId;
      profile.position = positionNew.positionName;
      profile.employeeOc = posMaster?.orgRoot?.orgRootName ?? null;
      profile.positionEmployeePositionId = positionNew.positionName;
      //   profile.positionEmployeeLineId = "PERM";
      //   profile.positionEmployeeGroupId = "PERM";

      await this.profileRepository.save(profile);
      await this.employeePositionRepository.save(positionNew);
    }
    await CreatePosMasterHistoryEmployee(posMaster.id, request);
    return new HttpSuccess();
  }

  /**
   * API ประวัติแก้ไขตำแหน่ง
   *
   * @summary ประวัติแก้ไขตำแหน่ง (ADMIN)
   *
   */
  @Get("history-update/{id}")
  async listPosMasterHistory(@Path() id: string, @Request() request: RequestWithUser) {
    const posMasterHistory = await this.posMasterHistoryRepository.find({
      where: { ancestorDNA: id },
      order: { createdAt: "DESC" },
    });

    return new HttpSuccess(posMasterHistory);
  }
}
