import {
  Controller,
  Get,
  Post,
  Delete,
  Route,
  Security,
  Tags,
  Body,
  Path,
  Request,
  Response,
} 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 { PosMasterAct } from "../entities/PosMasterAct";
import { PosMaster } from "../entities/PosMaster";
import { Brackets, In, IsNull, LessThan, MoreThan, Not } from "typeorm";
import permission from "../interfaces/permission";
import { OrgRevision } from "../entities/OrgRevision";
import Extension from "../interfaces/extension";
import { ProfileActposition } from "../entities/ProfileActposition";
import { RequestWithUser } from "../middlewares/user";
import { escape } from "querystring";
import { promisify } from "util";

const REDIS_HOST = process.env.REDIS_HOST;
const REDIS_PORT = process.env.REDIS_PORT;

@Route("api/v1/org/pos/act")
@Tags("PosMasterAct")
@Security("bearerAuth")
@Response(
  HttpStatusCode.INTERNAL_SERVER_ERROR,
  "เกิดข้อผิดพลาด ไม่สามารถแสดงรายการได้ กรุณาลองใหม่ในภายหลัง",
)
export class PosMasterActController extends Controller {
  private orgRevisionRepository = AppDataSource.getRepository(OrgRevision);
  private posMasterActRepository = AppDataSource.getRepository(PosMasterAct);
  private posMasterRepository = AppDataSource.getRepository(PosMaster);
  private actpositionRepository = AppDataSource.getRepository(ProfileActposition);
  private redis = require("redis");

  /**
   * API เพิ่มรักษาการในตำแหน่ง
   *
   * @summary เพิ่มรักษาการในตำแหน่ง (ADMIN)
   *
   */
  @Post()
  async createPosMasterAct(
    @Body() requestBody: { posMasterId: string; posMasterChildId: string },
    @Request() request: { user: Record<string, any> },
  ) {
    const posMaster = await this.posMasterRepository.findOne({
      where: {
        id: requestBody.posMasterId,
      },
    });
    if (posMaster == null) {
      throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูลตำแหน่งนี้");
    }

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

    const posMasterActOld = await this.posMasterActRepository.findOne({
      where: {
        posMasterId: requestBody.posMasterId,
      },
      order: { posMasterOrder: "DESC" },
    });
    let num = 0;
    if (posMasterActOld != null) {
      num = posMasterActOld.posMasterOrder;
    }

    const posMasterAct = new PosMasterAct();
    posMasterAct.posMasterOrder = num + 1;
    posMasterAct.posMasterId = requestBody.posMasterId;
    posMasterAct.posMasterChildId = requestBody.posMasterChildId;
    posMasterAct.createdUserId = request.user.sub;
    posMasterAct.createdFullName = request.user.name;
    posMasterAct.lastUpdateUserId = request.user.sub;
    posMasterAct.lastUpdateFullName = request.user.name;
    posMasterAct.createdAt = new Date();
    posMasterAct.lastUpdatedAt = new Date();
    await this.posMasterActRepository.save(posMasterAct);
    return new HttpSuccess(posMasterAct);
  }

  /**
   * API ค้นหาตำแหน่งในระบบสมัครสอบ ขรก.
   *
   * @summary ค้นหาตำแหน่งในระบบสมัครสอบ ขรก.
   *
   */
  @Post("search")
  async searchAct(
    @Request() request: RequestWithUser,
    @Body()
    body: {
      posmasterId: string;
      isAll: boolean;
      isAllRoot?: boolean;
      page?: number;
      pageSize?: number;
      keyword?: string;
    },
  ) {
    await new permission().PermissionGet(request, "SYS_ACTING");

    const { page = 1, pageSize = 100, keyword } = body;

    const posMasterMain = await this.posMasterRepository.findOne({
      where: { id: body.posmasterId },
      relations: ["posMasterActs"],
    });

    if (!posMasterMain) {
      throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูลประเภทตำแหน่งนี้");
    }

    let posId: any[] = posMasterMain.posMasterActs.map((x) => x.posMasterChildId);
    posId.push(body.posmasterId);

    const query = await AppDataSource.getRepository(PosMaster)
      .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("current_holder.posLevel", "posLevel")
      .leftJoinAndSelect("current_holder.posType", "posType")
      .where("posMaster.current_holderId IS NOT NULL")
      .andWhere("posMaster.id NOT IN (:...posId)", { posId });

    if (!body.isAllRoot) {
      if (body.isAll) {
        if (posMasterMain.orgChild4Id) {
          query.andWhere("posMaster.orgChild4Id = :id", {
            id: posMasterMain.orgChild4Id,
          });
        } else if (posMasterMain.orgChild3Id) {
          query.andWhere("posMaster.orgChild3Id = :id", {
            id: posMasterMain.orgChild3Id,
          });
        } else if (posMasterMain.orgChild2Id) {
          query.andWhere("posMaster.orgChild2Id = :id", {
            id: posMasterMain.orgChild2Id,
          });
        } else if (posMasterMain.orgChild1Id) {
          query.andWhere("posMaster.orgChild1Id = :id", {
            id: posMasterMain.orgChild1Id,
          });
        } else {
          query.andWhere("posMaster.orgRootId = :id", {
            id: posMasterMain.orgRootId,
          });
        }
      } else {
        query
          .andWhere(
            posMasterMain.orgRootId == null
              ? "posMaster.orgRootId IS NULL"
              : "posMaster.orgRootId = :orgRootId",
            { orgRootId: posMasterMain.orgRootId },
          )
          .andWhere(
            posMasterMain.orgChild1Id == null
              ? "posMaster.orgChild1Id IS NULL"
              : "posMaster.orgChild1Id = :orgChild1Id",
            { orgChild1Id: posMasterMain.orgChild1Id },
          )
          .andWhere(
            posMasterMain.orgChild2Id == null
              ? "posMaster.orgChild2Id IS NULL"
              : "posMaster.orgChild2Id = :orgChild2Id",
            { orgChild2Id: posMasterMain.orgChild2Id },
          )
          .andWhere(
            posMasterMain.orgChild3Id == null
              ? "posMaster.orgChild3Id IS NULL"
              : "posMaster.orgChild3Id = :orgChild3Id",
            { orgChild3Id: posMasterMain.orgChild3Id },
          )
          .andWhere(
            posMasterMain.orgChild4Id == null
              ? "posMaster.orgChild4Id IS NULL"
              : "posMaster.orgChild4Id = :orgChild4Id",
            { orgChild4Id: posMasterMain.orgChild4Id },
          );
      }
    } else {
      query.andWhere("posMaster.orgRootId = :orgRootId", {
        orgRootId: posMasterMain.orgRootId,
      });
    }

    if (keyword) {
      query.andWhere(
        new Brackets((qb) => {
          qb.where(
            `CONCAT(current_holder.prefix, current_holder.firstName, ' ', current_holder.lastName) LIKE :keyword`,
            { keyword: `%${keyword}%` },
          )
            .orWhere(`current_holder.citizenId LIKE :keyword`, {
              keyword: `%${keyword}%`,
            })
            .orWhere(
              `CONCAT(
                CASE
                  WHEN orgChild4.id IS NOT NULL THEN orgChild4.orgChild4ShortName
                  WHEN orgChild3.id IS NOT NULL THEN orgChild3.orgChild3ShortName
                  WHEN orgChild2.id IS NOT NULL THEN orgChild2.orgChild2ShortName
                  WHEN orgChild1.id IS NOT NULL THEN orgChild1.orgChild1ShortName
                  WHEN orgRoot.id IS NOT NULL THEN orgRoot.orgRootShortName
                  ELSE ''
                END,
                ' ',
                posMaster.posMasterNo
              ) LIKE :keyword`,
              { keyword: `%${keyword}%` },
            )
            .orWhere(`posLevel.posLevelName LIKE :keyword`, {
              keyword: `%${keyword}%`,
            })
            .orWhere(`posType.posTypeName LIKE :keyword`, {
              keyword: `%${keyword}%`,
            })
            .orWhere(`current_holder.position LIKE :keyword`, {
              keyword: `%${keyword}%`,
            });
        }),
      );
    }

    query.skip((page - 1) * pageSize).take(pageSize);

    const [posMaster, total] = await query.getManyAndCount();

    const data = await Promise.all(
      posMaster
        .sort((a, b) => a.posMasterOrder - b.posMasterOrder)
        .map((item) => {
          const shortName =
            item.orgChild4 != null
              ? `${item.orgChild4.orgChild4ShortName} ${item.posMasterNo}`
              : item?.orgChild3 != null
                ? `${item.orgChild3.orgChild3ShortName} ${item.posMasterNo}`
                : item?.orgChild2 != null
                  ? `${item.orgChild2.orgChild2ShortName} ${item.posMasterNo}`
                  : item?.orgChild1 != null
                    ? `${item.orgChild1.orgChild1ShortName} ${item.posMasterNo}`
                    : item?.orgRoot != null
                      ? `${item.orgRoot.orgRootShortName} ${item.posMasterNo}`
                      : null;
          return {
            id: item.id,
            citizenId: item.current_holder?.citizenId ?? null,
            isDirector: item.isDirector ?? null,
            prefix: item.current_holder?.prefix ?? null,
            firstName: item.current_holder?.firstName ?? null,
            lastName: item.current_holder?.lastName ?? null,
            posLevel: item.current_holder?.posLevel?.posLevelName ?? null,
            posType: item.current_holder?.posType?.posTypeName ?? null,
            position: item.current_holder?.position ?? null,
            posNo: shortName,
          };
        }),
    );
    return new HttpSuccess({ data: data, total });
  }

  /**
   * API ลบรักษาการในตำแหน่ง
   *
   * @summary ลบรักษาการในตำแหน่ง (ADMIN)
   *
   * @param {string} id  Id รักษาการในตำแหน่ง
   */
  @Delete("{id}")
  async deletePosMasterAct(@Path() id: string) {
    let result: any;
    const posMasterAct = await this.posMasterActRepository.findOne({
      where: {
        id: id,
      },
      relations: ["posMasterChild", "posMasterChild.current_holder"],
    });
    try {
      result = await this.posMasterActRepository.delete({ id: id });
    } catch {
      throw new HttpError(
        HttpStatusCode.NOT_FOUND,
        "ไม่สามารถลบได้เนื่องจากมีการใช้งานระดับตำแหน่งนี้อยู่",
      );
    }
    if (result.affected == undefined || result.affected <= 0) {
      throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูล");
    }

    if (posMasterAct != null) {
      const posMasterActList = await this.posMasterActRepository.find({
        where: {
          posMasterId: posMasterAct.posMasterId,
        },
      });
      posMasterActList.forEach(async (p, i) => {
        p.posMasterOrder = i + 1;
        await this.posMasterActRepository.save(p);
      });
    }

    // ลบ Redis cache ของคนที่เป็น acting
    if (posMasterAct != null && posMasterAct.posMasterChild?.current_holderId) {
      const profileId = posMasterAct.posMasterChild.current_holderId;
      const redisClient = await this.redis.createClient({
        host: REDIS_HOST,
        port: REDIS_PORT,
      });

      const delAsync = promisify(redisClient.del).bind(redisClient);
      await delAsync("role_" + profileId);
      await delAsync("menu_" + profileId);

      redisClient.quit();
    }

    return new HttpSuccess();
  }

  /**
   * API สลับรักษาการในตำแหน่ง
   *
   * @summary สลับรักษาการในตำแหน่ง (ADMIN)
   *
   */
  @Get("swap/{direction}/{posMasterActId}")
  async swapPosMasterAct(
    @Path() direction: string,
    posMasterActId: string,
    @Request() request: { user: Record<string, any> },
  ) {
    const source_item = await this.posMasterActRepository.findOne({
      where: {
        id: posMasterActId,
      },
    });
    if (source_item == null) throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูลตำแหน่งนี้");
    const sourceOrder = source_item.posMasterOrder;

    if (direction.trim().toUpperCase() == "UP") {
      const dest_item = await this.posMasterActRepository.findOne({
        where: { posMasterId: source_item.posMasterId, posMasterOrder: LessThan(sourceOrder) },
        order: { posMasterOrder: "DESC" },
      });
      if (dest_item == null) return new HttpSuccess();
      var destOrder = dest_item.posMasterOrder;
      dest_item.posMasterOrder = sourceOrder;
      source_item.posMasterOrder = destOrder;
      await Promise.all([
        this.posMasterActRepository.save(source_item),
        this.posMasterActRepository.save(dest_item),
      ]);
    } else {
      const dest_item = await this.posMasterActRepository.findOne({
        where: { posMasterId: source_item.posMasterId, posMasterOrder: MoreThan(sourceOrder) },
        order: { posMasterOrder: "ASC" },
      });
      if (dest_item == null) return new HttpSuccess();
      var destOrder = dest_item.posMasterOrder;
      dest_item.posMasterOrder = sourceOrder;
      source_item.posMasterOrder = destOrder;
      await Promise.all([
        this.posMasterActRepository.save(source_item),
        this.posMasterActRepository.save(dest_item),
      ]);
    }
    return new HttpSuccess();
  }

  /**
   * API รายชื่อรักษาการในตำแหน่ง
   *
   * @summary รายชื่อรักษาการในตำแหน่ง (ADMIN)
   *
   * @param {string} id  Id รักษาการในตำแหน่ง
   */
  @Get("profile")
  async GetPosMasterActProfile() {
    const orgRevisionActive = await this.orgRevisionRepository.findOne({
      where: { orgRevisionIsCurrent: true, orgRevisionIsDraft: false },
    });
    if (!orgRevisionActive) {
      return new HttpSuccess();
    }
    const posMasterActs = await this.posMasterActRepository.find({
      relations: [
        "posMaster",
        "posMasterChild",
        "posMasterChild.orgRoot",
        "posMasterChild.orgChild1",
        "posMasterChild.orgChild2",
        "posMasterChild.orgChild3",
        "posMasterChild.orgChild4",
        "posMasterChild.current_holder",
        "posMasterChild.current_holder.posLevel",
        "posMasterChild.current_holder.posType",
      ],
      where: {
        posMaster: {
          orgRevisionId: orgRevisionActive.id,
        },
      },
    });
    if (!posMasterActs) {
      throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูลประเภทตำแหน่งนี้");
    }

    const data = await Promise.all(
      posMasterActs
        .sort((a, b) => a.posMaster.posMasterOrder - b.posMaster.posMasterOrder)
        .map((item) => {
          const shortName =
            item.posMasterChild != null && item.posMasterChild.orgChild4 != null
              ? `${item.posMasterChild.orgChild4.orgChild4ShortName} ${item.posMasterChild.posMasterNo}`
              : item.posMasterChild != null && item.posMasterChild?.orgChild3 != null
                ? `${item.posMasterChild.orgChild3.orgChild3ShortName} ${item.posMasterChild.posMasterNo}`
                : item.posMasterChild != null && item.posMasterChild?.orgChild2 != null
                  ? `${item.posMasterChild.orgChild2.orgChild2ShortName} ${item.posMasterChild.posMasterNo}`
                  : item.posMasterChild != null && item.posMasterChild?.orgChild1 != null
                    ? `${item.posMasterChild.orgChild1.orgChild1ShortName} ${item.posMasterChild.posMasterNo}`
                    : item.posMasterChild != null && item.posMasterChild?.orgRoot != null
                      ? `${item.posMasterChild.orgRoot.orgRootShortName} ${item.posMasterChild.posMasterNo}`
                      : null;
          return {
            id: item.id,
            posMasterOrder: item.posMasterOrder,
            profileId: item.posMasterChild?.current_holder?.id ?? null,
            citizenId: item.posMasterChild?.current_holder?.citizenId ?? null,
            prefix: item.posMasterChild?.current_holder?.prefix ?? null,
            firstName: item.posMasterChild?.current_holder?.firstName ?? null,
            lastName: item.posMasterChild?.current_holder?.lastName ?? null,
            posLevel: item.posMasterChild?.current_holder?.posLevel?.posLevelName ?? null,
            posType: item.posMasterChild?.current_holder?.posType?.posTypeName ?? null,
            position: item.posMasterChild?.current_holder?.position ?? null,
            posNo: shortName,
          };
        }),
    );
    return new HttpSuccess(data);
  }

  /**
   * API รายชื่อรักษาการในตำแหน่ง
   *
   * @summary รายชื่อรักษาการในตำแหน่ง (ADMIN)
   *
   * @param {string} id  Id รักษาการในตำแหน่ง
   */
  @Get("{posMasterActId}/{profileId}")
  async GetPosMasterActProfileReport(
    @Path() posMasterActId: string,
    profileId: string,
    @Request() request: { user: Record<string, any> },
  ) {
    const posMasterAct = await this.posMasterActRepository.findOne({
      relations: [
        "posMaster",
        "posMaster",
        "posMaster.orgRoot",
        "posMaster.orgChild1",
        "posMaster.orgChild2",
        "posMaster.orgChild3",
        "posMaster.orgChild4",
        "posMaster.current_holder",
        "posMasterChild",
        "posMasterChild.orgRoot",
        "posMasterChild.orgChild1",
        "posMasterChild.orgChild2",
        "posMasterChild.orgChild3",
        "posMasterChild.orgChild4",
        "posMasterChild.current_holder",
        "posMasterChild.current_holder.posLevel",
        "posMasterChild.current_holder.posType",
      ],
      where: {
        id: posMasterActId,
      },
    });
    if (!posMasterAct) {
      throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูลประเภทตำแหน่งนี้");
    }
    const organization = [
      posMasterAct.posMasterChild?.current_holder?.position ?? null,
      posMasterAct.posMasterChild?.orgChild4?.orgChild4Name ?? null,
      posMasterAct.posMasterChild?.orgChild3?.orgChild3Name ?? null,
      posMasterAct.posMasterChild?.orgChild2?.orgChild2Name ?? null,
      posMasterAct.posMasterChild?.orgChild1?.orgChild1Name ?? null,
      posMasterAct.posMasterChild?.orgRoot?.orgRootName ?? null,
    ];
    const _organization = organization
      .filter((part) => part !== undefined && part !== null)
      .join(" ");

    const organizationNew = [
      posMasterAct.posMaster?.current_holder?.position ?? null,
      posMasterAct.posMaster?.orgChild4?.orgChild4Name ?? null,
      posMasterAct.posMaster?.orgChild3?.orgChild3Name ?? null,
      posMasterAct.posMaster?.orgChild2?.orgChild2Name ?? null,
      posMasterAct.posMaster?.orgChild1?.orgChild1Name ?? null,
      posMasterAct.posMaster?.orgRoot?.orgRootName ?? null,
    ];
    const _organizationNew = organizationNew
      .filter((part) => part !== undefined && part !== null)
      .join(" ");
    return new HttpSuccess({
      prefix: posMasterAct.posMasterChild?.current_holder?.prefix ?? null,
      firstName: posMasterAct.posMasterChild?.current_holder?.firstName ?? null,
      lastName: posMasterAct.posMasterChild?.current_holder?.lastName ?? null,
      organization: _organization, //
      position: posMasterAct.posMasterChild?.current_holder?.position ?? null,
      postype: posMasterAct.posMasterChild?.current_holder?.posType?.posTypeName ?? null,
      poslevel: posMasterAct.posMasterChild?.current_holder?.posLevel?.posLevelName ?? null,
      organizationNew: _organizationNew,
      date: Extension.ToThaiShortDate_noPrefix(new Date()),
      order:
        posMasterAct.posMasterOrder == null
          ? "-"
          : "ลำดับที่ " + Extension.ToThaiNumber(posMasterAct.posMasterOrder.toString()),
    });
  }

  /**
   * API รายละเอียดรักษาการในตำแหน่ง
   *
   * @summary รายละเอียดรักษาการในตำแหน่ง (ADMIN)
   *
   * @param {string} id  Id รักษาการในตำแหน่ง
   */
  @Get("{id}")
  async GetPosMasterActDetail(@Path() id: string) {
    const posMaster = await this.posMasterRepository.findOne({
      relations: [
        "posMasterActs",
        "posMasterActs.posMasterChild",
        "posMasterActs.posMasterChild.orgRoot",
        "posMasterActs.posMasterChild.orgChild1",
        "posMasterActs.posMasterChild.orgChild2",
        "posMasterActs.posMasterChild.orgChild3",
        "posMasterActs.posMasterChild.orgChild4",
        "posMasterActs.posMasterChild.current_holder",
        "posMasterActs.posMasterChild.current_holder.posLevel",
        "posMasterActs.posMasterChild.current_holder.posType",
      ],
      where: { id: id },
    });
    if (!posMaster) {
      throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูลประเภทตำแหน่งนี้");
    }

    const data = await Promise.all(
      posMaster.posMasterActs
        .sort((a, b) => a.posMasterOrder - b.posMasterOrder)
        .map((item) => {
          const shortName =
            item.posMasterChild != null && item.posMasterChild.orgChild4 != null
              ? `${item.posMasterChild.orgChild4.orgChild4ShortName} ${item.posMasterChild.posMasterNo}`
              : item.posMasterChild != null && item.posMasterChild?.orgChild3 != null
                ? `${item.posMasterChild.orgChild3.orgChild3ShortName} ${item.posMasterChild.posMasterNo}`
                : item.posMasterChild != null && item.posMasterChild?.orgChild2 != null
                  ? `${item.posMasterChild.orgChild2.orgChild2ShortName} ${item.posMasterChild.posMasterNo}`
                  : item.posMasterChild != null && item.posMasterChild?.orgChild1 != null
                    ? `${item.posMasterChild.orgChild1.orgChild1ShortName} ${item.posMasterChild.posMasterNo}`
                    : item.posMasterChild != null && item.posMasterChild?.orgRoot != null
                      ? `${item.posMasterChild.orgRoot.orgRootShortName} ${item.posMasterChild.posMasterNo}`
                      : null;
          return {
            id: item.id,
            posMasterOrder: item.posMasterOrder,
            citizenId: item.posMasterChild?.current_holder?.citizenId ?? null,
            prefix: item.posMasterChild?.current_holder?.prefix ?? null,
            firstName: item.posMasterChild?.current_holder?.firstName ?? null,
            lastName: item.posMasterChild?.current_holder?.lastName ?? null,
            posLevel: item.posMasterChild?.current_holder?.posLevel?.posLevelName ?? null,
            posType: item.posMasterChild?.current_holder?.posType?.posTypeName ?? null,
            position: item.posMasterChild?.current_holder?.position ?? null,
            posNo: shortName,
            statusReport: item.statusReport,
          };
        }),
    );
    return new HttpSuccess(data);
  }

  /**
   * API รายชื่อตามกลุ่มในรักษาการแทน
   *
   * @summary รายชื่อตามกลุ่มในรักษาการแทน
   *
   */
  @Post("report/draft")
  async reportDraft(
    @Body()
    body: {
      type: string;
      rootId: string;
    },
  ) {
    let conditionGroup = "";
    if (body.type.trim().toUpperCase() == "GROUP1.1") {
      conditionGroup =
        "(posTypeAct.posTypeName = 'ทั่วไป' AND posLevelAct.posLevelName = 'ชำนาญงาน') OR (posTypeAct.posTypeName = 'ทั่วไป' AND posLevelAct.posLevelName = 'ปฏิบัติงาน') OR (posTypeAct.posTypeName = 'วิชาการ' AND posLevelAct.posLevelName = 'ปฏิบัติการ') OR (posTypeAct.posTypeName = 'วิชาการ' AND posLevelAct.posLevelName = 'ชำนาญการ')";
    } else if (body.type.trim().toUpperCase() == "GROUP1.2") {
      conditionGroup =
        "(posTypeAct.posTypeName = 'ทั่วไป' AND posLevelAct.posLevelName = 'อาวุโส') OR (posTypeAct.posTypeName = 'วิชาการ' AND posLevelAct.posLevelName = 'ชำนาญการพิเศษ') OR (posTypeAct.posTypeName = 'อำนวยการ' AND posLevelAct.posLevelName = 'ต้น')";
    } else if (body.type.trim().toUpperCase() == "GROUP2") {
      conditionGroup =
        "(posTypeAct.posTypeName = 'ทั่วไป' AND posLevelAct.posLevelName = 'ทักษะพิเศษ') OR (posTypeAct.posTypeName = 'วิชาการ' AND posLevelAct.posLevelName = 'เชี่ยวชาญ') OR (posTypeAct.posTypeName = 'วิชาการ' AND posLevelAct.posLevelName = 'ทรงคุณวุฒิ') OR (posTypeAct.posTypeName = 'อำนวยการ' AND posLevelAct.posLevelName = 'สูง') OR (posTypeAct.posTypeName = 'บริหาร' AND posLevelAct.posLevelName = 'ต้น') OR (posTypeAct.posTypeName = 'บริหาร' AND posLevelAct.posLevelName = 'สูง')";
    } else {
      throw new HttpError(HttpStatusCode.NOT_FOUND, "กลุ่มเป้าหมายไม่ถูกต้อง");
    }

    let posMaster = await AppDataSource.getRepository(PosMasterAct)
      .createQueryBuilder("posMasterAct")
      .leftJoinAndSelect("posMasterAct.posMasterChild", "posMasterChild")
      .leftJoinAndSelect("posMasterChild.orgRoot", "orgRoot")
      .leftJoinAndSelect("posMasterChild.orgChild1", "orgChild1")
      .leftJoinAndSelect("posMasterChild.orgChild2", "orgChild2")
      .leftJoinAndSelect("posMasterChild.orgChild3", "orgChild3")
      .leftJoinAndSelect("posMasterChild.orgChild4", "orgChild4")
      .leftJoinAndSelect("posMasterChild.current_holder", "current_holder")
      .leftJoinAndSelect("posMasterChild.positions", "positions")
      .leftJoinAndSelect("positions.posType", "posType")
      .leftJoinAndSelect("positions.posLevel", "posLevel")
      .leftJoinAndSelect("posMasterAct.posMaster", "posMaster")
      .leftJoinAndSelect("posMaster.positions", "positionActs")
      .leftJoinAndSelect("posMaster.orgRoot", "orgRootAct")
      .leftJoinAndSelect("posMaster.orgChild1", "orgChild1Act")
      .leftJoinAndSelect("posMaster.orgChild2", "orgChild2Act")
      .leftJoinAndSelect("posMaster.orgChild3", "orgChild3Act")
      .leftJoinAndSelect("posMaster.orgChild4", "orgChild4Act")
      .leftJoinAndSelect("positionActs.posType", "posTypeAct")
      .leftJoinAndSelect("positionActs.posLevel", "posLevelAct")
      .leftJoinAndSelect("posMasterChild.orgRevision", "orgRevision")
      .andWhere("posMasterChild.orgRootId LIKE :orgRootId", {
        orgRootId: body.type.trim().toUpperCase() == "GROUP1.1" ? body.rootId : `%%`,
      })
      .andWhere("posMasterAct.statusReport = :statusReport", { statusReport: "PENDING" })
      .andWhere("posMasterChild.current_holderId IS NOT NULL")
      .andWhere("orgRevision.orgRevisionIsCurrent = :orgRevisionIsCurrent", {
        orgRevisionIsCurrent: true,
      })
      .andWhere("orgRevision.orgRevisionIsDraft = :orgRevisionIsDraft", {
        orgRevisionIsDraft: false,
      })
      .andWhere("positions.positionIsSelected = :isSelected", { isSelected: true })
      // .andWhere("positionActs.positionIsSelected = :isSelected", { isSelected: true })
      .andWhere(
        new Brackets((qb) => {
          qb.andWhere(conditionGroup);
        }),
      )
      .orderBy("posMasterAct.posMasterOrder", "ASC")
      .select([
        "posMasterAct.id",
        "posMasterChild.posMasterNo",
        "positions.positionName",
        "positions.positionIsSelected",
        "posType.posTypeName",
        "posLevel.posLevelName",
        "orgRoot.orgRootShortName",
        "orgChild1.orgChild1ShortName",
        "orgChild2.orgChild2ShortName",
        "orgChild3.orgChild3ShortName",
        "orgChild4.orgChild4ShortName",
        "posMaster.posMasterNo",
        "orgRootAct.orgRootShortName",
        "orgChild1Act.orgChild1ShortName",
        "orgChild2Act.orgChild2ShortName",
        "orgChild3Act.orgChild3ShortName",
        "orgChild4Act.orgChild4ShortName",
        "current_holder.prefix",
        "current_holder.firstName",
        "current_holder.lastName",
        "current_holder.id",
        "current_holder.citizenId",
      ])
      .getMany();
    const _posMaster = posMaster.map((x) => {
      const posMasterNo =
        [
          x.posMasterChild?.orgChild4?.orgChild4ShortName,
          x.posMasterChild?.orgChild3?.orgChild3ShortName,
          x.posMasterChild?.orgChild2?.orgChild2ShortName,
          x.posMasterChild?.orgChild1?.orgChild1ShortName,
          x.posMasterChild?.orgRoot?.orgRootShortName,
        ].find((name) => !!name) && x.posMasterChild?.posMasterNo
          ? `${[
              x.posMasterChild?.orgChild4?.orgChild4ShortName,
              x.posMasterChild?.orgChild3?.orgChild3ShortName,
              x.posMasterChild?.orgChild2?.orgChild2ShortName,
              x.posMasterChild?.orgChild1?.orgChild1ShortName,
              x.posMasterChild?.orgRoot?.orgRootShortName,
            ].find((name) => !!name)} ${x.posMasterChild.posMasterNo}`
          : x.posMasterChild?.posMasterNo || null;
      const orgShortNameAct =
        [
          x.posMaster?.orgChild4?.orgChild4ShortName,
          x.posMaster?.orgChild3?.orgChild3ShortName,
          x.posMaster?.orgChild2?.orgChild2ShortName,
          x.posMaster?.orgChild1?.orgChild1ShortName,
          x.posMaster?.orgRoot?.orgRootShortName,
        ].find((name) => !!name) || "";
      const posMasterNoAct =
        orgShortNameAct && x.posMaster?.posMasterNo
          ? `${orgShortNameAct} ${x.posMaster.posMasterNo}`
          : x.posMaster?.posMasterNo || null;
      const position =
        x.posMasterChild.positions.filter((x) => x.positionIsSelected == true).length > 0
          ? x.posMasterChild.positions.filter((x) => x.positionIsSelected == true)[0]
          : null;
      return {
        id: x.id,
        posMasterNo: posMasterNo,
        posMasterNoAct: posMasterNoAct,
        positionName: position?.positionName || null,
        posType: position?.posType?.posTypeName || null,
        posLevel: position?.posLevel?.posLevelName || null,
        profileId: x.posMasterChild?.current_holder?.id || null,
        prefix: x.posMasterChild?.current_holder?.prefix || null,
        firstName: x.posMasterChild?.current_holder?.firstName || null,
        lastName: x.posMasterChild?.current_holder?.lastName || null,
        citizenId: x.posMasterChild?.current_holder?.citizenId || null,
      };
    });

    return new HttpSuccess(_posMaster);
  }

  /**
   * API รักษาการในตำแหน่ง active โดยไม่ต้องออกคำสั่ง
   * @summary รักษาการในตำแหน่ง active ในระบบโดยไม่ต้องออกคำสั่ง (SUPER ADMIN)
   * @param {string} id  Id หน่วยงาน
   */
  @Post("{id}")
  async activePosMasterAct(@Path() id: string, @Request() req: { user: Record<string, any> }) {
    const posMasterActs = await this.posMasterActRepository
      .createQueryBuilder("posMasterAct")
      .leftJoinAndSelect("posMasterAct.posMaster", "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("posMasterAct.posMasterChild", "posMasterChild")
      .where("posMaster.orgRootId = :orgRootId", { orgRootId: id })
      .andWhere("posMasterAct.statusReport = :statusReport", { statusReport: "PENDING" })
      .select([
        "posMasterAct.id",
        "posMasterAct.statusReport",
        "posMaster.posMasterNo",
        "orgRoot.orgRootShortName",
        "orgChild1.orgChild1ShortName",
        "orgChild2.orgChild2ShortName",
        "orgChild3.orgChild3ShortName",
        "orgChild4.orgChild4ShortName",
        "current_holder.position",
        "posMasterChild.current_holderId",
      ])
      .getMany();

    if (posMasterActs.length === 0) {
      throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูลรักษาการในตำแหน่งของหน่วยงานนี้");
    }

    // เก็บรวบรวม profileIds ทั้งหมดเพื่อ clear cache หลังจากบันทึกเสร็จ
    const profileIdsToClearCache = new Set<string>();

    await Promise.all(
      posMasterActs.map(async (posMasterAct) => {
        const orgShortName =
          [
            posMasterAct.posMaster?.orgChild4?.orgChild4ShortName,
            posMasterAct.posMaster?.orgChild3?.orgChild3ShortName,
            posMasterAct.posMaster?.orgChild2?.orgChild2ShortName,
            posMasterAct.posMaster?.orgChild1?.orgChild1ShortName,
            posMasterAct.posMaster?.orgRoot?.orgRootShortName,
          ].find(Boolean) ?? "";

        const profileId = posMasterAct.posMasterChild?.current_holderId;

        if (profileId) {
          profileIdsToClearCache.add(profileId);

          const existingActivePositions = await this.actpositionRepository.find({
            select: [
              "id",
              "status",
              "lastUpdateUserId",
              "lastUpdateFullName",
              "lastUpdatedAt",
              "dateEnd",
              "isDeleted",
            ],
            where: { profileId, status: true, isDeleted: false },
          });

          if (existingActivePositions.length > 0) {
            await Promise.all(
              existingActivePositions.map(async (pos) => {
                Object.assign(pos, {
                  status: false,
                  lastUpdateUserId: req.user?.sub ?? null,
                  lastUpdateFullName: req.user?.name ?? null,
                  lastUpdatedAt: new Date(),
                  dateEnd: new Date(),
                });
                await this.actpositionRepository.save(pos);
              }),
            );
          }
        }

        const dataAct = new ProfileActposition();
        Object.assign(dataAct, {
          profileId: profileId ?? null,
          dateStart: new Date(),
          posNo:
            orgShortName && posMasterAct.posMaster?.posMasterNo
              ? `${orgShortName} ${posMasterAct.posMaster.posMasterNo}`
              : posMasterAct.posMaster?.posMasterNo ?? "-",
          position: posMasterAct.posMaster?.current_holder?.position ?? null,
          posNoAbb: orgShortName,
          status: true,
          createdUserId: req.user?.sub ?? null,
          createdFullName: req.user?.name ?? null,
          lastUpdateUserId: req.user?.sub ?? null,
          lastUpdateFullName: req.user?.name ?? null,
        });
        await this.actpositionRepository.save(dataAct);

        posMasterAct.statusReport = "DONE";
        await this.posMasterActRepository.save(posMasterAct);
      }),
    );

    // Clear Redis cache หลังจากบันทึกข้อมูลเสร็จแล้ว
    // ทำงานนอก loop เพื่อ clear รอบเดียว ไม่ใช่ทุก iteration
    if (profileIdsToClearCache.size > 0) {
      await Promise.all(
        Array.from(profileIdsToClearCache).map(async (profileId) => {
          const redisClient = await this.redis.createClient({
            host: REDIS_HOST,
            port: REDIS_PORT,
          });

          const delAsync = promisify(redisClient.del).bind(redisClient);
          await delAsync("role_" + profileId);
          await delAsync("menu_" + profileId);

          redisClient.quit();
        }),
      );
    }
    return new HttpSuccess();
  }
}
