import { Body, Controller, Get, Path, Post, Put, Request, Route, Security, Tags } from "tsoa";
import { AppDataSource } from "../database/data-source";
import { RequestWithUser } from "../middlewares/user";
import HttpError from "../interfaces/http-error";
import HttpStatus from "../interfaces/http-status";
import HttpSuccess from "../interfaces/http-success";
import { Workflow } from "../entities/Workflow";
import { State } from "../entities/State";
import { StateOperator } from "../entities/StateOperator";
import { StateOperatorUser } from "../entities/StateOperatorUser";
import CallAPI from "../interfaces/call-api";
import { Profile } from "../entities/Profile";
import { StateUserComment } from "../entities/StateUserComment";
import { MetaWorkflow } from "../entities/MetaWorkflow";
import { MetaState } from "../entities/MetaState";
import { MetaStateOperator } from "../entities/MetaStateOperator";
import { PosMaster } from "../entities/PosMaster";
import { Brackets, IsNull, Not, In } from "typeorm";
import { Assign } from "../entities/Assign";
import { PosMasterAct } from "../entities/PosMasterAct";
import { viewDirectorActing } from "../entities/view/viewDirectorActing";
import { viewDirector } from "../entities/view/viewDirector";
import { ProfileEmployee } from "../entities/ProfileEmployee";
import { EmployeePosMaster } from "../entities/EmployeePosMaster";
import { OrgRoot } from "../entities/OrgRoot";
import { getPosMasterPositions } from "../services/PositionService";
@Route("api/v1/org/workflow")
@Tags("Workflow")
@Security("bearerAuth")
export class WorkflowController extends Controller {
  private workflowRepo = AppDataSource.getRepository(Workflow);
  private stateRepo = AppDataSource.getRepository(State);
  private stateOperatorRepo = AppDataSource.getRepository(StateOperator);
  private stateOperatorUserRepo = AppDataSource.getRepository(StateOperatorUser);
  private stateUserCommentRepo = AppDataSource.getRepository(StateUserComment);
  private profileRepo = AppDataSource.getRepository(Profile);
  private profileEmployeeRepo = AppDataSource.getRepository(ProfileEmployee);
  private orgRootRepo = AppDataSource.getRepository(OrgRoot);
  private metaWorkflowRepo = AppDataSource.getRepository(MetaWorkflow);
  private metaStateRepo = AppDataSource.getRepository(MetaState);
  private metaStateOperatorRepo = AppDataSource.getRepository(MetaStateOperator);
  private posMasterRepo = AppDataSource.getRepository(PosMaster);
  private posMasterEmpRepo = AppDataSource.getRepository(EmployeePosMaster);
  private posMasterActRepo = AppDataSource.getRepository(PosMasterAct);
  private assignRepo = AppDataSource.getRepository(Assign);

  @Post("add-workflow")
  public async checkWorkflow(
    @Request() req: RequestWithUser,
    @Body()
    body: {
      refId: string;
      sysName: string;
      posLevelName: string;
      posTypeName: string;
      fullName?: string | null;
      isDeputy?: boolean | null;
      orgRootId?: string | null;
    },
  ) {
    // ขั้นที่ 1: ทำการค้นหา profile และ metaWorkflow แบบ parallel
    const [userProfileOfficer, userProfileEmployee, metaWorkflow] = await Promise.all([
      this.profileRepo.findOne({
        where: { keycloak: req.user.sub },
        select: ["id", "keycloak"],
      }),
      this.profileEmployeeRepo.findOne({
        where: { keycloak: req.user.sub },
        select: ["id", "keycloak"],
      }),
      this.metaWorkflowRepo.findOne({
        where: {
          sysName: body.sysName,
          posLevelName: body.posLevelName,
          posTypeName: body.posTypeName,
        },
      }),
    ]);

    // กำหนด profile type และ profile
    let profileType = "OFFICER";
    let profile: any = userProfileOfficer;

    if (!profile) {
      profileType = "EMPLOYEE";
      profile = userProfileEmployee;
      if (!profile) throw new HttpError(HttpStatus.NOT_FOUND, "ไม่พบข้อมูลผู้ใช้งาน");
    }

    if (!metaWorkflow) throw new HttpError(HttpStatus.NOT_FOUND, "ไม่พบกระบวนการนี้ได้");

    const meta = {
      createdUserId: req.user.sub,
      createdFullName: req.user.name,
      lastUpdateUserId: req.user.sub,
      lastUpdateFullName: req.user.name,
      createdAt: new Date(),
      lastUpdatedAt: new Date(),
    };

    // ขั้นที่ 2: สร้าง workflow และดึง metaState แบบ parallel
    const workflow = new Workflow();
    Object.assign(workflow, {
      ...metaWorkflow,
      id: undefined,
      ...meta,
      ...body,
      profileType: profileType,
      system: body.sysName,
    });

    const [savedWorkflow, metaStates] = await Promise.all([
      this.workflowRepo.save(workflow),
      this.metaStateRepo.find({
        where: { metaWorkflowId: metaWorkflow.id },
        order: { order: "ASC" },
      }),
    ]);

    // ขั้นที่ 3: สร้าง states ทั้งหมดในครั้งเดียว
    const statesToCreate = metaStates.map((item) => {
      const state = new State();
      Object.assign(state, { ...item, id: undefined, workflowId: savedWorkflow.id, ...meta });
      return state;
    });

    const savedStates = await this.stateRepo.save(statesToCreate);

    // ขั้นที่ 4: อัปเดต workflow.stateId กับ state แรก
    const firstState = savedStates.find((state) => state.order === 1);
    if (firstState) {
      savedWorkflow.stateId = firstState.id;
      await this.workflowRepo.save(savedWorkflow);
    }

    // ขั้นที่ 5: ดึง metaStateOperators ทั้งหมดและสร้าง stateOperators
    const metaStateIds = metaStates.map((item) => item.id);
    const allMetaStateOperators = await this.metaStateOperatorRepo.find({
      where: { metaStateId: In(metaStateIds) },
    });

    // สร้าง stateOperators ทั้งหมดในครั้งเดียว
    const stateOperatorsToCreate: StateOperator[] = [];
    allMetaStateOperators.forEach((metaStateOp) => {
      const correspondingState = savedStates.find(
        (state) =>
          metaStates.find((metaState) => metaState.id === metaStateOp.metaStateId)?.order ===
          state.order,
      );
      if (body.isDeputy) {
        // Task #2207 กรณีคนขอโอนอยู่ในสำนักปลัดกรุงเทพมหานคร
        if (body.sysName == "SYS_TRANSFER_REQ") {
          if (metaStateOp.operator == "PersonnelOfficer" && correspondingState?.order == 1) {
            return;
          } else if (
            metaStateOp.operator == "Officer" &&
            [1, 2].includes(correspondingState?.order as number)
          ) {
            metaStateOp.operator = "PersonnelOfficer";
          }
        }
        // Task #2208 กรณีขอแก้ไขข้อมูลทะเบียนประวัติ และ IDP และคนขออยู่ในสำนักปลัดกรุงเทพมหานคร
        if (
          metaStateOp.operator == "Officer" &&
          ["REGISTRY_PROFILE", "REGISTRY_PROFILE_EMP", "REGISTRY_IDP"].includes(body.sysName)
        ) {
          metaStateOp.operator = "PersonnelOfficer";
        }
      }
      if (correspondingState) {
        const stateOperator = new StateOperator();
        Object.assign(stateOperator, {
          ...metaStateOp,
          id: undefined,
          stateId: correspondingState.id,
          ...meta,
        });
        stateOperatorsToCreate.push(stateOperator);
      }
    });

    await this.stateOperatorRepo.save(stateOperatorsToCreate);
    // ขั้นที่ 6: สร้าง StateOperatorUsers แบบ bulk
    const stateOperatorUsersToCreate: StateOperatorUser[] = [];
    let orderNum = 1;

    // เพิ่ม Owner ก่อน
    if (profile) {
      const ownerStateOperatorUser = new StateOperatorUser();
      Object.assign(ownerStateOperatorUser, {
        profileId: profileType === "OFFICER" ? profile.id : null,
        profileEmployeeId: profileType !== "OFFICER" ? profile.id : null,
        profileType: profileType,
        operator: "Owner",
        order: orderNum,
        workflowId: savedWorkflow.id,
        ...meta,
      });
      stateOperatorUsersToCreate.push(ownerStateOperatorUser);
    }

    // ดึงข้อมูล profileOfficers และสร้าง StateOperatorUsers
    const profileOfficers = await this.posMasterRepo.find({
      where: {
        posMasterAssigns: { assignId: body.sysName },
        orgRevision: { orgRevisionIsDraft: false, orgRevisionIsCurrent: true },
        current_holderId: Not(IsNull()), // เพิ่มเงื่อนไขนี้เพื่อกรองเฉพาะที่มี current_holder
        ...(body.orgRootId && { orgRootId: body.orgRootId }), // กรองเฉพาะที่อยู่ในสำนักเดียวกัน (ถ้าส่งมา)
      },
      relations: ["orgChild1"],
      // select: ["current_holderId", "orgChild1"], // เลือกเฉพาะ field ที่จำเป็น
    });

    // สร้าง StateOperatorUsers สำหรับ officers
    profileOfficers.forEach((item) => {
      if (item.current_holderId) {
        orderNum += 1;
        const isPersonnelOfficer = item.orgChild1?.isOfficer === true;

        const officerStateOperatorUser = new StateOperatorUser();
        Object.assign(officerStateOperatorUser, {
          profileId: item.current_holderId,
          operator: isPersonnelOfficer ? "PersonnelOfficer" : "Officer",
          profileType: "OFFICER",
          order: orderNum,
          workflowId: savedWorkflow.id,
          ...meta,
        });
        stateOperatorUsersToCreate.push(officerStateOperatorUser);
      }
    });

    // บันทึก StateOperatorUsers ทั้งหมดในครั้งเดียว
    await this.stateOperatorUserRepo.save(stateOperatorUsersToCreate);

    // ขั้นที่ 7: ส่ง notification (ใช้ข้อมูลที่มีอยู่แล้วแทนการ query ใหม่)
    const firstStateOperators = stateOperatorsToCreate.filter((so) =>
      savedStates.find((state) => state.id === so.stateId && state.order === 1),
    );

    // add link sysName = REGISTRY_PROFILE or REGISTRY_PROFILE_EMP
    let notiLink = "";
    if (body.sysName === "REGISTRY_PROFILE") {
      notiLink = `${process.env.VITE_URL_MGT}/registry-officer/request-edit/personal/${body.refId}`;
    } else if (body.sysName === "REGISTRY_PROFILE_EMP") {
      notiLink = `${process.env.VITE_URL_MGT}/registry-employee/request-edit/personal/${body.refId}`;
    } else if (body.sysName === "REGISTRY_IDP") {
      notiLink = `${process.env.VITE_URL_MGT}/registry-officer/request-edit-page/${body.refId}`;
    }

    const notificationReceivers = stateOperatorUsersToCreate
      .filter((user) => firstStateOperators.some((op) => op.operator === user.operator))
      .map((user) => ({
        receiverUserId: user.profileType === "OFFICER" ? user.profileId : user.profileEmployeeId,
        notiLink: notiLink,
      }));

    // ส่ง notification แบบ fire-and-forget
    new CallAPI()
      .PostData(req, "/placement/noti/profiles", {
        subject: `แจ้ง${savedWorkflow.name}ของ ${body.fullName}`,
        body: `แจ้ง${savedWorkflow.name}ของ ${body.fullName}`,
        receiverUserIds: notificationReceivers,
        payload: "",
        isSendMail: true,
        isSendInbox: true,
        isSendNotification: true,
      })
      .catch((error) => {
        console.error("Error calling API:", error);
      });

    return new HttpSuccess();
  }

  @Post("check-iscan")
  public async checkIsCan(
    @Request() req: RequestWithUser,
    @Body()
    body: {
      workflowId: string;
      stateId: string;
      profileId: string;
      action: string;
    },
  ) {
    let stateOperatorUser = await this.stateOperatorUserRepo.findOne({
      where: {
        profileId: body.profileId,
        workflowId: body.workflowId,
      },
    });
    if (!stateOperatorUser) {
      stateOperatorUser = await this.stateOperatorUserRepo.findOne({
        where: {
          profileEmployeeId: body.profileId,
          workflowId: body.workflowId,
        },
      });
      if (!stateOperatorUser)
        throw new HttpError(HttpStatus.NOT_FOUND, "ผู้ใช้งานนี้ไม่มีหน้าที่ในกระบวนการนี้");
    }

    const operator = await this.stateOperatorRepo.findOne({
      where: {
        operator: stateOperatorUser.operator,
        state: { id: body.stateId, workflow: { id: body.workflowId } },
      },
    });
    if (!operator) throw new HttpError(HttpStatus.NOT_FOUND, "ไม่สามารถดำเนินการกระบวนการนี้ได้");

    let isCan = false;
    switch (body.action.trim().toLocaleUpperCase()) {
      case "VIEW":
        isCan = operator.canView;
      case "UPDATE":
        isCan = operator.canUpdate;
      case "DELETE":
        isCan = operator.canDelete;
      case "CANCEL":
        isCan = operator.canCancel;
      case "OPERATE":
        isCan = operator.canOperate;
      case "CHANGESTATE":
        isCan = operator.canChangeState;
      case "COMMENT":
        isCan = operator.canComment;
      case "SIGN":
        isCan = operator.canSign;
      default:
        isCan = false;
    }
    if (isCan == false) {
      throw new HttpError(HttpStatus.NOT_FOUND, "ไม่สามารถดำเนินการได้");
    } else {
      return new HttpSuccess();
    }
  }

  @Post("check-state-now")
  public async checkStateNow(
    @Request() req: RequestWithUser,
    @Body()
    body: {
      refId: string;
      system: string;
    },
  ) {
    const workflow = await this.workflowRepo.findOne({
      where: {
        refId: body.refId,
        sysName: body.system,
      },
      relations: ["stateOperatorUsers"],
    });
    if (!workflow) throw new HttpError(HttpStatus.NOT_FOUND, "ไม่สามารถดำเนินการกระบวนการนี้ได้");

    const state = await this.stateRepo.findOne({
      where: {
        id: workflow.stateId,
      },
      relations: ["stateOperators"],
    });
    if (!state) throw new HttpError(HttpStatus.NOT_FOUND, "ไม่พบข้อมูลขั้นตอนการอนุมัติ");
    return new HttpSuccess({
      stateId: state.id,
      stateNo: state.order,
      stateName: state.name,
    });
  }

  @Post("check-user-now")
  public async checkUserNow(
    @Request() req: RequestWithUser,
    @Body()
    body: {
      refId: string;
      system: string;
    },
  ) {
    const workflow = await this.workflowRepo.findOne({
      where: {
        refId: body.refId,
        sysName: body.system,
      },
    });
    if (!workflow) throw new HttpError(HttpStatus.NOT_FOUND, "ไม่สามารถดำเนินการกระบวนการนี้ได้");

    let stateOperatorUser = await this.stateOperatorUserRepo.findOne({
      where: {
        workflow: {
          refId: body.refId,
          sysName: body.system,
        },
        profile: {
          keycloak: req.user.sub,
        },
      },
      relations: ["workflow"],
    });
    if (!stateOperatorUser) {
      stateOperatorUser = await this.stateOperatorUserRepo.findOne({
        where: {
          workflow: {
            refId: body.refId,
            sysName: body.system,
          },
          profileEmployee: {
            keycloak: req.user.sub,
          },
        },
        relations: ["workflow"],
      });
    }
    const operator = await this.stateOperatorRepo.findOne({
      where: {
        operator: stateOperatorUser?.operator || "",
        stateId: workflow.stateId,
      },
      relations: ["state"],
    });
    if (!operator) {
      const state = await this.stateRepo.findOne({
        where: {
          id: workflow.stateId,
        },
      });
      return new HttpSuccess({
        stateId: state?.id || null,
        stateNo: state?.order || null,
        stateName: state?.name || null,
        operator: stateOperatorUser?.operator || null,
        can_view: false,
        can_update: false,
        can_operate: false,
        can_change_state: false,
        can_delete: false,
        can_cancel: false,
        can_sign: false,
        keycloakId: workflow.createdUserId,
      });
    }
    return new HttpSuccess({
      stateId: operator.state.id,
      stateNo: operator.state.order,
      stateName: operator.state.name,
      operator: operator.operator,
      can_view: operator.canView,
      can_update: operator.canUpdate,
      can_operate: operator.canOperate,
      can_change_state: operator.canChangeState,
      can_delete: operator.canDelete,
      can_cancel: operator.canCancel,
      can_sign: operator.canSign,
      keycloakId: workflow.createdUserId,
    });
  }

  @Post("check-state-all")
  public async checkStateAll(
    @Request() req: RequestWithUser,
    @Body()
    body: {
      refId: string;
      system: string;
    },
  ) {
    const state = await this.stateRepo.find({
      where: {
        workflow: {
          refId: body.refId,
          sysName: body.system,
        },
      },
      order: { order: "ASC", stateUserComments: { order: "ASC" } },
      relations: ["stateUserComments", "stateUserComments.profile"],
    });
    const _state = state.map((x) => ({
      stateId: x.id,
      stateNo: x.order,
      stateName: x.name,
      stateUserComments: x.stateUserComments.map((x) => ({
        id: x.id,
        prefix: x.profile.prefix,
        firstName: x.profile.firstName,
        lastName: x.profile.lastName,
        isComment: x.profile.keycloak == req.user.sub ? true : false,
        profileId: x.profileId,
        isAcceptSetting: x.isAcceptSetting,
        isApproveSetting: x.isApproveSetting,
        isReasonSetting: x.isReasonSetting,
        isAccept: x.isAccept,
        isApprove: x.isApprove,
        reason: x.reason,
      })),
    }));
    return new HttpSuccess(_state);
  }

  @Post("state-next")
  public async stateNext(
    @Request() req: RequestWithUser,
    @Body()
    body: {
      refId: string;
      system: string;
    },
  ) {
    const workflow = await this.workflowRepo.findOne({
      where: {
        refId: body.refId,
        sysName: body.system,
      },
      relations: ["stateOperatorUsers"],
    });
    if (!workflow) throw new HttpError(HttpStatus.NOT_FOUND, "ไม่สามารถดำเนินการกระบวนการนี้ได้");

    let stateOperatorUserNow = await this.stateOperatorUserRepo.findOne({
      where: {
        workflow: {
          refId: body.refId,
          sysName: body.system,
        },
        profile: {
          keycloak: req.user.sub,
        },
      },
    });
    if (!stateOperatorUserNow) {
      stateOperatorUserNow = await this.stateOperatorUserRepo.findOne({
        where: {
          workflow: {
            refId: body.refId,
            sysName: body.system,
          },
          profileEmployee: {
            keycloak: req.user.sub,
          },
        },
      });
    }
    let stateOperatorUser = await this.stateOperatorUserRepo.find({
      where: {
        workflow: {
          refId: body.refId,
          sysName: body.system,
        },
        profile: {
          keycloak: Not(req.user.sub),
        },
        operator: stateOperatorUserNow?.operator || "",
      },
    });
    if (!stateOperatorUser) {
      stateOperatorUser = await this.stateOperatorUserRepo.find({
        where: {
          workflow: {
            refId: body.refId,
            sysName: body.system,
          },
          profileEmployee: {
            keycloak: Not(req.user.sub),
          },
          operator: stateOperatorUserNow?.operator || "",
        },
      });
    }
    await this.stateOperatorUserRepo.remove(stateOperatorUser);

    const state = await this.stateRepo.findOne({
      where: {
        id: workflow.stateId,
      },
      relations: ["stateOperators"],
    });
    if (!state) throw new HttpError(HttpStatus.NOT_FOUND, "ไม่พบข้อมูลขั้นตอนการอนุมัติ");
    const _state = await this.stateRepo.findOne({
      where: {
        order: state.order + 1,
        workflowId: state.workflowId,
      },
      relations: ["stateOperators"],
    });
    //noti
    let profileNow = workflow.stateOperatorUsers
      .filter((x) => state.stateOperators.map((s) => s.operator).includes(x.operator))
      .map((x) => ({
        receiverUserId: x.profileType == "OFFICER" ? x.profileId : x.profileEmployeeId,
        notiLink: "",
      }));
    await new CallAPI()
      .PostData(req, "/placement/noti/profiles", {
        subject: `รายการถูกส่ง`,
        body: `รายการถูกส่ง`,
        receiverUserIds: profileNow,
        payload: "", //แนบไฟล์
        isSendMail: true,
        isSendInbox: true,
        isSendNotification: true,
      })
      .catch((error) => {
        console.error("Error calling API:", error);
      });
    if (_state != null) {
      let profileNext = workflow.stateOperatorUsers
        .filter((x) => _state.stateOperators.map((s) => s.operator).includes(x.operator))
        .map((x) => ({
          receiverUserId: x.profileType == "OFFICER" ? x.profileId : x.profileEmployeeId,
          notiLink: "",
        }));
      await new CallAPI()
        .PostData(req, "/placement/noti/profiles", {
          subject: `ได้รับรายการ ${workflow.name}`,
          body: `ได้รับรายการ ${workflow.name}`,
          receiverUserIds: profileNext,
          payload: "", //แนบไฟล์
          isSendMail: true,
          isSendInbox: true,
          isSendNotification: true,
        })
        .catch((error) => {
          console.error("Error calling API:", error);
        });
      workflow.stateId = _state.id;
      await this.workflowRepo.save(workflow);
    }

    return new HttpSuccess({
      stateId: _state?.id || null,
      stateNo: _state?.order || null,
      stateName: _state?.name || null,
      stateType: _state?.type || null,
    });
  }

  @Post("state-back")
  public async stateBack(
    @Request() req: RequestWithUser,
    @Body()
    body: {
      stateId: string;
    },
  ) {
    const state = await this.stateRepo.findOne({
      where: {
        id: body.stateId,
      },
    });
    if (!state) throw new HttpError(HttpStatus.NOT_FOUND, "ไม่พบข้อมูลขั้นตอนการอนุมัติ");
    const _state = await this.stateRepo.findOne({
      where: {
        order: state.order - 1,
        workflowId: state.workflowId,
      },
    });

    return new HttpSuccess({
      stateId: _state?.id || null,
      stateNo: _state?.order || null,
      stateName: _state?.name || null,
      stateType: _state?.type || null,
    });
  }

  @Post("add-step")
  public async addStep(
    @Request() req: RequestWithUser,
    @Body()
    body: {
      stateId: string;
      profileId: string;
      isAcceptSetting: boolean;
      isApproveSetting: boolean;
      isReasonSetting: boolean;
    },
  ) {
    const profile = await this.profileRepo.findOne({
      where: {
        id: body.profileId,
      },
    });
    if (!profile) throw new HttpError(HttpStatus.NOT_FOUND, "ไม่พบผู้ใช้งานนี้");
    const state = await this.stateRepo.findOne({
      where: {
        id: body.stateId,
      },
      relations: ["stateUserComments", "workflow"],
    });
    if (!state) throw new HttpError(HttpStatus.NOT_FOUND, "ไม่พบข้อมูลขั้นตอนการอนุมัติ");

    if (state.stateUserComments.filter((x) => x.profileId == body.profileId).length > 0)
      throw new HttpError(HttpStatus.NOT_FOUND, "ไม่สามารถเลือกซ้ำได้");

    const stateUserComment = new StateUserComment();
    stateUserComment.order = state.stateUserComments.length + 1;
    stateUserComment.stateId = body.stateId;
    stateUserComment.profileId = body.profileId;
    stateUserComment.isAcceptSetting = body.isAcceptSetting;
    stateUserComment.isApproveSetting = body.isApproveSetting;
    stateUserComment.isReasonSetting = body.isReasonSetting;
    stateUserComment.createdUserId = req.user.sub;
    stateUserComment.createdFullName = req.user.name;
    stateUserComment.createdAt = new Date();
    stateUserComment.lastUpdateUserId = req.user.sub;
    stateUserComment.lastUpdateFullName = req.user.name;
    stateUserComment.lastUpdatedAt = new Date();
    await this.stateUserCommentRepo.save(stateUserComment);
    state.workflow.sysName;
    const assign = await this.assignRepo.findOne({
      where: {
        id: state.workflow.sysName,
      },
    });
    if (!assign) throw new HttpError(HttpStatus.NOT_FOUND, "ไม่พบข้อมูลขั้นตอนการอนุมัติ");
    await new CallAPI()
      .PostData(req, "/placement/noti/profiles", {
        subject: `ได้รับรายการ ${state.workflow.name}`,
        body: `ได้รับรายการ ${state.workflow.name}`,
        receiverUserIds: [
          {
            receiverUserId: body.profileId,
            notiLink: `${process.env.VITE_URL_MGT}/${assign.path}/${state.workflow.refId}`,
          },
        ],
        payload: "", //แนบไฟล์
        isSendMail: true,
        isSendInbox: true,
        isSendNotification: true,
      })
      .catch((error) => {
        console.error("Error calling API:", error);
      });

    return new HttpSuccess();
  }

  @Post("comment")
  public async createcomment(
    @Request() req: RequestWithUser,
    @Body()
    body: {
      stateUserCommentId: string;
      isAccept?: boolean | null;
      isApprove?: boolean | null;
      reason?: string | null;
    },
  ) {
    const stateUserComment = await this.stateUserCommentRepo.findOne({
      where: {
        id: body.stateUserCommentId,
      },
      relations: ["state", "state.workflow", "state.stateOperators"],
    });
    if (!stateUserComment)
      throw new HttpError(HttpStatus.NOT_FOUND, "ไม่พบข้อมูลขั้นตอนการอนุมัติ");
    stateUserComment.state.stateOperators;

    const workflow = await this.workflowRepo.findOne({
      where: {
        refId: stateUserComment.state.workflow.refId,
        sysName: stateUserComment.state.workflow.sysName,
      },
      relations: ["stateOperatorUsers"],
    });
    if (!workflow) throw new HttpError(HttpStatus.NOT_FOUND, "ไม่สามารถดำเนินการกระบวนการนี้ได้");
    let profileNow = workflow.stateOperatorUsers
      .filter((x) =>
        stateUserComment.state.stateOperators.map((s) => s.operator).includes(x.operator),
      )
      .map((x) => ({
        receiverUserId: x.profileType == "OFFICER" ? x.profileId : x.profileEmployeeId,
        notiLink: "",
      }));
    await new CallAPI()
      .PostData(req, "/placement/noti/profiles", {
        subject: `ผู้บังคับบัญชาดำเนินการ`,
        body: `ผู้บังคับบัญชาดำเนินการ`,
        receiverUserIds: profileNow,
        payload: "", //แนบไฟล์
        isSendMail: true,
        isSendInbox: true,
        isSendNotification: true,
      })
      .catch((error) => {
        console.error("Error calling API:", error);
      });
    let _null: any = null;
    stateUserComment.isAccept = body.isAccept == null ? _null : body.isAccept;
    stateUserComment.isApprove = body.isApprove == null ? _null : body.isApprove;
    stateUserComment.reason = body.reason == null ? _null : body.reason;
    stateUserComment.lastUpdateUserId = req.user.sub;
    stateUserComment.lastUpdateFullName = req.user.name;
    stateUserComment.lastUpdatedAt = new Date();
    await this.stateUserCommentRepo.save(stateUserComment);

    return new HttpSuccess();
  }

  @Post("comment-state")
  public async getCommentState(
    @Request() req: RequestWithUser,
    @Body()
    body: {
      stateId: string;
    },
  ) {
    const state = await this.stateRepo.findOne({
      where: {
        id: body.stateId,
      },
      order: { stateUserComments: { order: "ASC" } },
      relations: ["stateUserComments"],
    });
    if (!state) throw new HttpError(HttpStatus.NOT_FOUND, "ไม่พบข้อมูลขั้นตอนการอนุมัติ");

    return new HttpSuccess(state.stateUserComments);
  }

  @Post("comment-state-user")
  public async getCommentStateUser(
    @Request() req: RequestWithUser,
    @Body()
    body: {
      stateId: string;
    },
  ) {
    const stateUserComment = await this.stateUserCommentRepo.findOne({
      where: {
        profile: {
          keycloak: req.user.sub,
        },
        stateId: body.stateId,
      },
    });

    return new HttpSuccess({
      id: stateUserComment?.id || null,
      isAccept: stateUserComment?.isAccept || null,
      isApprove: stateUserComment?.isApprove || null,
      reason: stateUserComment?.reason || null,
      isAcceptSetting: stateUserComment?.isAcceptSetting || null,
      isApproveSetting: stateUserComment?.isApproveSetting || null,
      isReasonSetting: stateUserComment?.isReasonSetting || null,
      order: stateUserComment?.order || null,
      stateId: stateUserComment?.stateId || null,
      profileId: stateUserComment?.profileId || null,
    });
  }

  /**
   *
   *
   */
  @Put("commander/{type}")
  async getProfilePlacement(
    @Request() request: RequestWithUser,
    @Path() type: string,
    @Body()
    body: {
      isAct: boolean;
      keyword: string;
      page: number;
      pageSize: number;
      keycloakId?: string | null;
      type?: string | null;
      sortBy?: string | null;
      descending?: boolean;
    },
  ) {
    const userKeycloak = body.keycloakId ?? request.user.sub;

    // 1. Cache user lookup - ใช้ select เฉพาะ field ที่จำเป็น
    const userSelectFields = {
      id: true,
      orgRootId: true,
      orgChild1Id: true,
      orgChild2Id: true,
      orgChild3Id: true,
      orgChild4Id: true,
      orgRevisionId: true,
      current_holder: {
        id: true,
        posType: { id: true, posTypeName: true },
        posLevel: { id: true, posLevelName: true },
      },
    };

    let posMasterUser: any = null;

    if (body.type === "employee") {
      posMasterUser = await this.posMasterEmpRepo.findOne({
        where: {
          orgRevision: { orgRevisionIsCurrent: true, orgRevisionIsDraft: false },
          current_holder: { keycloak: userKeycloak },
        },
        select: userSelectFields,
        relations: ["current_holder", "current_holder.posType", "current_holder.posLevel"],
      });
    } else {
      posMasterUser = await this.posMasterRepo.findOne({
        where: {
          orgRevision: { orgRevisionIsCurrent: true, orgRevisionIsDraft: false },
          current_holder: { keycloak: userKeycloak },
        },
        select: userSelectFields,
        relations: ["current_holder", "current_holder.posType", "current_holder.posLevel"],
      });
    }

    if (!posMasterUser?.orgRootId) {
      throw new HttpError(HttpStatus.NOT_FOUND, "ไม่พบตำแหน่งผู้ใช้งาน");
    }

    // Task #2342 list ปลัด และรองปลัดใน popup ผู้บังคับบัญชา และผู้มีอำนาจเพิ่ม
    const roodIds = [posMasterUser.orgRootId];
    const orgRoot = await this.orgRootRepo.findOne({
      select: { id: true, isDeputy: true },
      where: {
        id: Not(posMasterUser.orgRootId),
        isDeputy: true,
        orgRevision: { orgRevisionIsCurrent: true, orgRevisionIsDraft: false },
      },
    });
    if (orgRoot && orgRoot.isDeputy) {
      roodIds.push(orgRoot.id);
    }

    // 2. Pre-calculate conditions - ย้ายออกมาข้างนอก
    const posType = posMasterUser.current_holder?.posType?.posTypeName;
    const posLevel = posMasterUser.current_holder?.posLevel?.posLevelName;

    const isLowLevel =
      (posType === "ทั่วไป" && ["ชำนาญงาน", "ปฏิบัติงาน"].includes(posLevel)) ||
      (posType === "วิชาการ" && ["ปฏิบัติการ", "ชำนาญการ"].includes(posLevel));

    const isMidLevel =
      (posType === "ทั่วไป" && posLevel === "อาวุโส") ||
      (posType === "วิชาการ" && posLevel === "ชำนาญการพิเศษ") ||
      (posType === "อำนวยการ" && posLevel === "ต้น");

    // 3. สร้าง conditions แบบ optimized
    const baseCondition = {
      isDirector: true,
      orgRevisionId: posMasterUser.orgRevisionId,
    };

    const conditionOfficer = {
      ...baseCondition,
      isOfficer: true,
      orgChild1Id: IsNull(),
    };

    let mainConditions: any[] = [];

    if (type.trim().toUpperCase() === "OPERATE" || body.type === "employee") {
      mainConditions = [
        { ...baseCondition, orgRootId: In(roodIds), orgChild1Id: IsNull() },
        {
          ...baseCondition,
          orgRootId: In(roodIds),
          orgChild1Id: posMasterUser.orgChild1Id,
          orgChild2Id: IsNull(),
        },
        {
          ...baseCondition,
          orgRootId: In(roodIds),
          orgChild1Id: posMasterUser.orgChild1Id,
          orgChild2Id: posMasterUser.orgChild2Id,
          orgChild3Id: IsNull(),
        },
        {
          ...baseCondition,
          orgRootId: In(roodIds),
          orgChild1Id: posMasterUser.orgChild1Id,
          orgChild2Id: posMasterUser.orgChild2Id,
          orgChild3Id: posMasterUser.orgChild3Id,
          orgChild4Id: IsNull(),
        },
        {
          ...baseCondition,
          orgRootId: In(roodIds),
          orgChild1Id: posMasterUser.orgChild1Id,
          orgChild2Id: posMasterUser.orgChild2Id,
          orgChild3Id: posMasterUser.orgChild3Id,
          orgChild4Id: posMasterUser.orgChild4Id,
        },
      ];
    } else if (isLowLevel) {
      mainConditions = [
        {
          ...baseCondition,
          orgRootId: In(roodIds),
          orgChild1Id: IsNull(),
          orgChild2Id: IsNull(),
          orgChild3Id: IsNull(),
          orgChild4Id: IsNull(),
        },
      ];
    } else if (isMidLevel) {
      mainConditions = [
        {
          ...baseCondition,
          isDeputy: true,
          orgChild1Id: IsNull(),
          orgChild2Id: IsNull(),
          orgChild3Id: IsNull(),
          orgChild4Id: IsNull(),
        },
      ];
    } else {
      mainConditions = [{ ...baseCondition, orgRootId: In(roodIds) }];
    }

    // 4. สร้าง optimized query builder
    const repository = body.isAct
      ? AppDataSource.getRepository(viewDirectorActing)
      : AppDataSource.getRepository(viewDirector);

    let queryBuilder = repository.createQueryBuilder("entity");

    // 5. แยก WHERE conditions ให้เร็วขึ้น
    queryBuilder.where(
      new Brackets((qb) => {
        mainConditions.forEach((condition, index) => {
          if (index === 0) {
            qb.where(condition);
          } else {
            qb.orWhere(condition);
          }
        });
        qb.orWhere(conditionOfficer);
      }),
    );

    // 6. ปรับ search conditions ให้เร็วขึ้น
    if (body.keyword?.trim()) {
      const keyword = `%${body.keyword.trim()}%`;
      const searchFields = [
        "CONCAT(entity.prefix, entity.firstName, ' ', entity.lastName)",
        "entity.citizenId",
        "entity.position",
        "entity.posLevel",
        "entity.posType",
        "entity.posNo",
        "entity.posExecutiveName",
      ];

      if (body.isAct) {
        searchFields.push("entity.actFullName");
      }

      queryBuilder.andWhere(
        `(${searchFields.map((field) => `${field} LIKE :keyword`).join(" OR ")})`,
        { keyword },
      );
    }

    if (body.sortBy) {
      queryBuilder = queryBuilder.orderBy(
        `entity.${body.sortBy === "posExecutiveNameOrg" ? "posExecutiveName" : body.sortBy}`,
        body.descending ? "DESC" : "ASC",
      );
    }

    // 7. Execute พร้อมกัน - ใช้ Promise.all
    const [data, total] = await Promise.all([
      queryBuilder
        .skip((body.page - 1) * body.pageSize)
        .take(body.pageSize)
        .getMany(),
      queryBuilder.getCount(),
    ]);

    // 8. ปรับ response mapping (ถ้าจำเป็น)
    let posMasterPositionMap: Map<string, string> = new Map();

    if (body.isAct) {
      // ดึง posMasterId ทั้งหมด (36 ตัวแรกของ key) เพื่อ query positionName
      const posMasterIds = data
        .map((x) => x.key?.substring(0, 36))
        .filter((id) => id && id.length === 36);
      posMasterPositionMap = await getPosMasterPositions(posMasterIds);
    }

    const processedData = data.map((x: any) => {
      let newPositionSign = x.positionSign;

      if (body.isAct) {
        // ตำแหน่งของคนที่เลือกไปรักษาการ
        let childPosition = "";
        if (x.positionSignChild) {
          childPosition = x.positionSignChild;
        } else if (x.posExecutiveName) {
          childPosition = x.posExecutiveName;
        } else {
          childPosition = `${x.position || ""}${x.posLevel || ""}`.trim();
        }

        // ตำแหน่งที่รักษาการแทน
        const posMasterId = x.key?.substring(0, 36);
        const targetPosition = x.positionSign
          ? x.positionSign
          : posMasterPositionMap.get(posMasterId) || "";

        // สร้าง positionSign ใหม่
        newPositionSign = `${childPosition} รักษาการในตำแหน่ง${targetPosition}`;
      }

      return {
        ...x,
        positionSign: newPositionSign,
        posExecutiveNameOrg:
          (x.posExecutiveName ?? "") +
          (x.orgChild4 ?? x.orgChild3 ?? x.orgChild2 ?? x.orgChild1 ?? x.orgRoot ?? ""),
      };
    });

    return new HttpSuccess({ data: processedData, total });
  }
  /**
   *
   *
   */
  @Put("commander-posexe/{type}")
  async getProfilePlacementPosExe(
    @Request() request: RequestWithUser,
    @Path() type: string,
    @Body()
    body: {
      isAct: boolean;
      keyword: string;
      page: number;
      pageSize: number;
      keycloakId?: string | null;
    },
  ) {
    const userKeycloak = body.keycloakId ?? request.user.sub;

    // 1. ใช้ select เฉพาะ field ที่จำเป็น - เหมือน getProfilePlacement
    const userSelectFields = {
      id: true,
      orgRootId: true,
      orgChild1Id: true,
      orgChild2Id: true,
      orgChild3Id: true,
      orgChild4Id: true,
      orgRevisionId: true,
      current_holder: {
        id: true,
        posType: { id: true, posTypeName: true },
        posLevel: { id: true, posLevelName: true },
      },
    };

    const posMasterUser = await this.posMasterRepo.findOne({
      where: {
        orgRevision: { orgRevisionIsCurrent: true, orgRevisionIsDraft: false },
        current_holder: { keycloak: userKeycloak },
      },
      select: userSelectFields,
      relations: ["current_holder", "current_holder.posType", "current_holder.posLevel"],
    });

    if (!posMasterUser?.orgRootId) {
      throw new HttpError(HttpStatus.NOT_FOUND, "ไม่พบตำแหน่งผู้ใช้งาน");
    }

    // 2. Pre-calculate conditions - ปรับให้เหมือน getProfilePlacement
    const posType = posMasterUser.current_holder?.posType?.posTypeName;
    const posLevel = posMasterUser.current_holder?.posLevel?.posLevelName;

    const isLowLevel =
      (posType === "ทั่วไป" && ["ชำนาญงาน", "ปฏิบัติงาน"].includes(posLevel)) ||
      (posType === "วิชาการ" && ["ปฏิบัติการ", "ชำนาญการ"].includes(posLevel));

    const isMidLevel =
      (posType === "ทั่วไป" && posLevel === "อาวุโส") ||
      (posType === "วิชาการ" && posLevel === "ชำนาญการพิเศษ") ||
      (posType === "อำนวยการ" && posLevel === "ต้น");

    // 3. สร้าง conditions แบบ optimized
    const baseCondition = {
      isDirector: true,
      orgRevisionId: posMasterUser.orgRevisionId,
    };

    const conditionOfficer = {
      ...baseCondition,
      isOfficer: true,
      orgChild1Id: IsNull(),
    };

    let mainConditions: any[] = [];

    if (type.trim().toUpperCase() === "OPERATE") {
      mainConditions = [
        { ...baseCondition, orgRootId: posMasterUser.orgRootId, orgChild1Id: IsNull() },
        {
          ...baseCondition,
          orgRootId: posMasterUser.orgRootId,
          orgChild1Id: posMasterUser.orgChild1Id,
          orgChild2Id: IsNull(),
        },
        {
          ...baseCondition,
          orgRootId: posMasterUser.orgRootId,
          orgChild1Id: posMasterUser.orgChild1Id,
          orgChild2Id: posMasterUser.orgChild2Id,
          orgChild3Id: IsNull(),
        },
        {
          ...baseCondition,
          orgRootId: posMasterUser.orgRootId,
          orgChild1Id: posMasterUser.orgChild1Id,
          orgChild2Id: posMasterUser.orgChild2Id,
          orgChild3Id: posMasterUser.orgChild3Id,
          orgChild4Id: IsNull(),
        },
        {
          ...baseCondition,
          orgRootId: posMasterUser.orgRootId,
          orgChild1Id: posMasterUser.orgChild1Id,
          orgChild2Id: posMasterUser.orgChild2Id,
          orgChild3Id: posMasterUser.orgChild3Id,
          orgChild4Id: posMasterUser.orgChild4Id,
        },
      ];
    } else if (isLowLevel) {
      mainConditions = [
        {
          ...baseCondition,
          orgRootId: posMasterUser.orgRootId,
          orgChild1Id: IsNull(),
          orgChild2Id: IsNull(),
          orgChild3Id: IsNull(),
          orgChild4Id: IsNull(),
        },
      ];
    } else if (isMidLevel) {
      mainConditions = [
        {
          ...baseCondition,
          isDeputy: true,
          orgChild1Id: IsNull(),
          orgChild2Id: IsNull(),
          orgChild3Id: IsNull(),
          orgChild4Id: IsNull(),
        },
      ];
    } else {
      mainConditions = [{ ...baseCondition, orgRootId: posMasterUser.orgRootId }];
    }

    // 4. สร้าง optimized query builder
    const repository = body.isAct
      ? AppDataSource.getRepository(viewDirectorActing)
      : AppDataSource.getRepository(viewDirector);

    const queryBuilder = repository.createQueryBuilder("entity");

    // 5. แยก WHERE conditions ให้เร็วขึ้น
    queryBuilder.where(
      new Brackets((qb) => {
        mainConditions.forEach((condition, index) => {
          if (index === 0) {
            qb.where(condition);
          } else {
            qb.orWhere(condition);
          }
        });
        qb.orWhere(conditionOfficer);
      }),
    );

    // 6. ปรับ search conditions ให้เร็วขึ้น - แบบเดียวกับ getProfilePlacement
    if (body.keyword?.trim()) {
      const keyword = `%${body.keyword.trim()}%`;
      const searchFields = [
        "CONCAT(entity.prefix, entity.firstName, ' ', entity.lastName)",
        "entity.citizenId",
        "entity.position",
        "entity.posLevel",
        "entity.posType",
        "entity.posNo",
        "entity.posExecutiveName",
      ];

      if (body.isAct) {
        searchFields.push("entity.actFullName");
      }

      queryBuilder.andWhere(
        `(${searchFields.map((field) => `${field} LIKE :keyword`).join(" OR ")})`,
        { keyword },
      );
    }

    // 7. Execute พร้อมกัน - ใช้ Promise.all
    const [data, total] = await Promise.all([
      queryBuilder
        .skip((body.page - 1) * body.pageSize)
        .take(body.pageSize)
        .getMany(),
      queryBuilder.getCount(),
    ]);

    // 8. ปรับ response mapping
    const processedData = data.map((x: any) => ({
      ...x,
      posExecutiveNameOrg:
        (x.posExecutiveName ?? "") +
        (x.orgChild4 ?? x.orgChild3 ?? x.orgChild2 ?? x.orgChild1 ?? x.orgRoot ?? ""),
    }));

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

  /**
   * API เช็ค สกจ
   *
   * @summary เช็ค สกจ
   *
   */
  @Get("keycloak/isofficer/{system}")
  async getIsOfficerByKeycloak(@Path() system: string, @Request() req: RequestWithUser) {
    const profile = await this.profileRepo.findOne({
      where: {
        keycloak: req.user.sub,
      },
    });
    if (!profile) throw new HttpError(HttpStatus.NOT_FOUND, "ไม่พบข้อมูลผู้ใช้งาน");

    const profileOfficer = await this.posMasterRepo.findOne({
      where: {
        posMasterAssigns: { assignId: system },
        orgRevision: { orgRevisionIsDraft: false, orgRevisionIsCurrent: true },
        current_holderId: profile.id,
      },
      relations: ["orgChild1", "orgRoot"],
    });
    const profileDirector = await this.posMasterRepo.findOne({
      where: {
        orgRevision: { orgRevisionIsDraft: false, orgRevisionIsCurrent: true },
        current_holderId: profile.id,
      },
    });
    if (!profileOfficer)
      return new HttpSuccess({
        isOfficer: false,
        isStaff: false,
        isDirector: profileDirector?.isDirector ?? false,
        isDeputy: false,
      });
    let isOfficer = profileOfficer.orgChild1 == null ? false : profileOfficer.orgChild1.isOfficer;
    return new HttpSuccess({
      isOfficer: isOfficer,
      isStaff: !isOfficer,
      isDirector: profileDirector?.isDirector ?? false,
      isDeputy: profileOfficer?.orgRoot?.isDeputy ?? false,
    });
  }

  /**
   * API เช็ค สกจ
   *
   * @summary เช็ค สกจ
   *
   */
  @Get("keycloak/isofficer-root/{system}")
  async getIsOfficerByKeycloakRoot(@Path() system: string, @Request() req: RequestWithUser) {
    const profile = await this.profileRepo.findOne({
      where: {
        keycloak: req.user.sub,
      },
    });
    if (!profile) throw new HttpError(HttpStatus.NOT_FOUND, "ไม่พบข้อมูลผู้ใช้งาน");

    const profileOfficer = await this.posMasterRepo.findOne({
      where: {
        posMasterAssigns: { assignId: system },
        orgRevision: { orgRevisionIsDraft: false, orgRevisionIsCurrent: true },
        current_holderId: profile.id,
      },
      relations: ["orgChild1"],
    });
    const profileDirector = await this.posMasterRepo.findOne({
      where: {
        orgRevision: { orgRevisionIsDraft: false, orgRevisionIsCurrent: true },
        current_holderId: profile.id,
      },
    });
    if (!profileOfficer)
      return new HttpSuccess({
        isOfficer: false,
        isStaff: false,
        isDirector: profileDirector?.isDirector ?? false,
      });
    let isOfficer = profileOfficer.orgChild1 == null ? false : profileOfficer.orgChild1.isOfficer;
    return new HttpSuccess({
      isOfficer: isOfficer,
      isStaff: !isOfficer,
      isDirector: profileDirector
        ? !profileDirector.orgChild1Id && profileDirector.orgRootId
          ? profileDirector.isDirector
          : false
        : false,
    });
  }

  /**
   * API เช็ค สกจ
   *
   * @summary เช็ค สกจ
   *
   */
  @Post("keycloak/isofficer")
  async checkPermissionWorkflow(
    @Request() req: RequestWithUser,
    @Body()
    body: {
      refId: string;
      sysName: string;
    },
  ) {
    const profile = await this.profileRepo.findOne({
      where: {
        keycloak: req.user.sub,
      },
    });
    if (!profile) throw new HttpError(HttpStatus.UNAUTHORIZED, "ไม่พบข้อมูลผู้ใช้งาน");

    const profileOfficer = await this.workflowRepo.findOne({
      where: {
        states: { stateUserComments: { profile: { keycloak: req.user.sub } } },
        refId: body.refId,
        // sysName: body.sysName,
      },
    });
    if (!profileOfficer) throw new HttpError(HttpStatus.FORBIDDEN, "ไม่พบข้อมูลสิทธิ์");
    return new HttpSuccess();
  }

  /**
   * API หาหัวหน้า
   *
   * @summary หาหัวหน้า
   *
   */
  @Post("find/director")
  async getProfileDirectorByProfileId(
    @Request() req: RequestWithUser,
    @Body()
    body: {
      refId: string[];
    },
  ) {
    const _posMaster = await this.posMasterRepo.find({
      where: {
        orgRevision: { orgRevisionIsDraft: false, orgRevisionIsCurrent: true },
        current_holderId: In(body.refId),
      },
      select: ["orgRootId", "orgChild1Id", "orgChild2Id", "orgChild3Id", "orgChild4Id"],
    });
    const _data: any = _posMaster.map((x) => ({
      orgRootId: x.orgRootId,
      orgChild1Id: x.orgChild1Id,
      orgChild2Id: x.orgChild2Id,
      orgChild3Id: x.orgChild3Id,
      orgChild4Id: x.orgChild4Id,
      isDirector: true,
      current_holder: Not(IsNull()),
    }));
    const posMaster = await this.posMasterRepo.find({
      where: _data,
      relations: ["current_holder"],
    });

    const data = posMaster.map((x) => ({
      id: x.current_holder.id,
      citizenId: x.current_holder.citizenId,
      prefix: x.current_holder.prefix,
      firstName: x.current_holder.firstName,
      lastName: x.current_holder.lastName,
    }));
    return new HttpSuccess(data);
  }

  /**
   * API หา กจ ตามระบบ
   *
   * @summary หา กจ ตามระบบ
   *
   */
  @Post("find/director/{system}")
  async getProfileDirectorByProfileIdSystem(
    @Request() req: RequestWithUser,
    @Path() system: string,
    @Body()
    body: {
      refId: string[];
    },
  ) {
    const _posMaster = await this.posMasterRepo.find({
      where: {
        orgRevision: { orgRevisionIsDraft: false, orgRevisionIsCurrent: true },
        current_holderId: In(body.refId),
      },
      select: ["orgRootId", "orgChild1Id", "orgChild2Id", "orgChild3Id", "orgChild4Id"],
    });

    const _data: any = _posMaster.map((x) => ({
      orgRootId: x.orgRootId,
      // orgChild1Id: x.orgChild1Id,
      // orgChild2Id: x.orgChild2Id,
      // orgChild3Id: x.orgChild3Id,
      // orgChild4Id: x.orgChild4Id,
      // isDirector: true,
      current_holder: Not(IsNull()),
      posMasterAssigns: { assignId: system.trim().toUpperCase() },
    }));

    const posMaster = await this.posMasterRepo.find({
      where: _data,
      relations: ["current_holder"],
    });

    const data = posMaster.map((x) => ({
      id: x.current_holder.id,
      citizenId: x.current_holder.citizenId,
      prefix: x.current_holder.prefix,
      firstName: x.current_holder.firstName,
      lastName: x.current_holder.lastName,
    }));

    return new HttpSuccess(data);
  }
  /**
   * API หา กจ ตามระบบด้วย keycloak
   *
   * @summary หา กจ ตามระบบด้วย keycloak
   *
   */
  @Post("find/director-with-keycloak/{system}")
  async getProfileDirectorByKeycloakIdSystem(
    @Request() req: RequestWithUser,
    @Path() system: string,
    @Body()
    body: {
      refId: string[];
    },
  ) {
    const profileWithKc = await this.profileRepo.find({
      where: {
        keycloak: In(body.refId),
      },
    });

    const profileIds = profileWithKc.map((p) => p.id);

    const _posMaster = await this.posMasterRepo.find({
      where: {
        orgRevision: {
          orgRevisionIsDraft: false,
          orgRevisionIsCurrent: true,
        },
        current_holderId: In(profileIds),
      },
      select: ["orgRootId", "orgChild1Id", "orgChild2Id", "orgChild3Id", "orgChild4Id"],
    });

    const _data: any = _posMaster.map((x) => ({
      orgRootId: x.orgRootId,
      // orgChild1Id: x.orgChild1Id,
      // orgChild2Id: x.orgChild2Id,
      // orgChild3Id: x.orgChild3Id,
      // orgChild4Id: x.orgChild4Id,
      // isDirector: true,
      current_holder: Not(IsNull()),
      posMasterAssigns: { assignId: system.trim().toUpperCase() },
    }));

    const posMaster = await this.posMasterRepo.find({
      where: _data,
      relations: ["current_holder"],
    });

    const data = posMaster.map((x) => ({
      id: x.current_holder.id,
      keycloak: x.current_holder.keycloak,
      citizenId: x.current_holder.citizenId,
      prefix: x.current_holder.prefix,
      firstName: x.current_holder.firstName,
      lastName: x.current_holder.lastName,
    }));

    return new HttpSuccess(data);
  }
}
