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, LessThan, MoreThan } from "typeorm";
import { OrgRevision } from "../entities/OrgRevision";
import Extension from "../interfaces/extension";

@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);

  /**
   * 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 ลบรักษาการในตำแหน่ง (ADMIN)
   *
   * @param {string} id  Id รักษาการในตำแหน่ง
   */
  @Delete("{id}")
  async deletePosMasterAct(@Path() id: string) {
    let result: any;
    const posMasterAct = await this.posMasterActRepository.findOne({
      where: {
        id: id,
      },
    });
    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);
      });
    }
    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,
          };
        }),
    );
    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);
  }
}
