import { Body, Controller, Example, Get, Patch, Path, Request, Route, Security, Tags } from "tsoa";
import { AppDataSource } from "../database/data-source";
import HttpSuccess from "../interfaces/http-success";
import HttpStatus from "../interfaces/http-status";
import HttpError from "../interfaces/http-error";
import { RequestWithUser } from "../middlewares/user";
import { ProfileEmployee } from "../entities/ProfileEmployee";
import { ProfileGovernment, UpdateProfileGovernment } from "../entities/ProfileGovernment";
import { EmployeePosition } from "../entities/EmployeePosition";
import { EmployeePosMaster } from "../entities/EmployeePosMaster";
import {
  calculateAge,
  calculateGovAge,
  calculateRetireDate,
  setLogDataDiff,
} from "../interfaces/utils";
import permission from "../interfaces/permission";
import { OrgRevision } from "../entities/OrgRevision";
import { In } from "typeorm";
import { ProfileSalary } from "../entities/ProfileSalary";
@Route("api/v1/org/profile-employee/government")
@Tags("ProfileEmployeeGovernment")
@Security("bearerAuth")
export class ProfileGovernmentEmployeeController extends Controller {
  private profileEmployeeRepo = AppDataSource.getRepository(ProfileEmployee);
  private govRepo = AppDataSource.getRepository(ProfileGovernment);
  private positionRepo = AppDataSource.getRepository(EmployeePosition);
  private posMasterRepo = AppDataSource.getRepository(EmployeePosMaster);
  private orgRevisionRepository = AppDataSource.getRepository(OrgRevision);
  private salaryRepo = AppDataSource.getRepository(ProfileSalary);
  /**
   *
   * @summary ข้อมูลราชการ
   *
   */
  @Get("user")
  public async getGovHistoryUser(@Request() request: { user: Record<string, any> }) {
    const orgRevision = await this.orgRevisionRepository.findOne({
      select: ["id"],
      where: {
        orgRevisionIsDraft: false,
        orgRevisionIsCurrent: true,
      },
    });
    const profile = await this.profileEmployeeRepo.findOneBy({ keycloak: request.user.sub });
    if (!profile) {
      throw new HttpError(HttpStatus.BAD_REQUEST, "ไม่พบ profile ดังกล่าว");
    }
    const record = await this.profileEmployeeRepo.findOne({
      where: { id: profile.id },
      relations: {
        posType: true,
        posLevel: true,
      },
    });
    const posMaster = await this.posMasterRepo.findOne({
      where: {
        // orgRevision: {
        //   orgRevisionIsCurrent: true,
        //   orgRevisionIsDraft: false,
        // },
        orgRevisionId: orgRevision?.id,
        current_holderId: profile.id,
      },
      order: { createdAt: "DESC" },
      relations: {
        orgRoot: true,
        orgChild1: true,
        orgChild2: true,
        orgChild3: true,
        orgChild4: true,
      },
    });
    // const position = await this.positionRepo.findOne({
    //   where: {
    //     positionIsSelected: true,
    //     posMaster: {
    //       orgRevision: {
    //         orgRevisionIsCurrent: true,
    //         orgRevisionIsDraft: false,
    //       },
    //       current_holderId: profile.id,
    //     },
    //   },
    //   order: { createdAt: "DESC" },
    // });

    if (!record) throw new HttpError(HttpStatus.NOT_FOUND, "ไม่พบข้อมูล");
    const fullNameParts = [
      posMaster == null || posMaster.orgChild4 == null ? null : posMaster.orgChild4.orgChild4Name,
      posMaster == null || posMaster.orgChild3 == null ? null : posMaster.orgChild3.orgChild3Name,
      posMaster == null || posMaster.orgChild2 == null ? null : posMaster.orgChild2.orgChild2Name,
      posMaster == null || posMaster.orgChild1 == null ? null : posMaster.orgChild1.orgChild1Name,
      posMaster == null || posMaster.orgRoot == null ? null : posMaster.orgRoot.orgRootName,
    ];
    const org = fullNameParts.filter((part) => part !== undefined && part !== null).join("\n");
    let orgShortName = "";
    if (posMaster != null) {
      if (posMaster.orgChild1Id === null) {
        orgShortName = posMaster.orgRoot?.orgRootShortName;
      } else if (posMaster.orgChild2Id === null) {
        orgShortName = posMaster.orgChild1?.orgChild1ShortName;
      } else if (posMaster.orgChild3Id === null) {
        orgShortName = posMaster.orgChild2?.orgChild2ShortName;
      } else if (posMaster.orgChild4Id === null) {
        orgShortName = posMaster.orgChild3?.orgChild3ShortName;
      } else {
        orgShortName = posMaster.orgChild4?.orgChild4ShortName;
      }
    }
    const data = {
      org: org, //สังกัด
      position: record.position, //ตำแหน่ง
      posLevel:
        record.posType == null && record.posLevel == null
          ? null
          : `${record.posType.posTypeShortName} ${record.posLevel.posLevelName}`, //ระดับ
      posMasterNo: posMaster == null ? null : `${orgShortName} ${[posMaster.posMasterNoPrefix, posMaster.posMasterNo, posMaster.posMasterNoSuffix].filter((p) => p !== null && p !== undefined && p !== '').join(' ')}`, //เลขที่ตำแหน่ง
      posType: record.posType == null ? null : record.posType.posTypeName, //ประเภท
      dateLeave: record.birthDate == null ? null : calculateRetireDate(record.birthDate),
      dateRetireLaw: record.dateRetireLaw ?? null,
      // govAge: record.dateStart == null ? null : calculateAge(record.dateStart),
      govAge: await calculateGovAge(profile.id, "EMPLOYEE"),
      govAgeBkk: await calculateGovAge(profile.id, "EMPLOYEE", true),
      dateAppoint: record.dateAppoint,
      dateStart: record.dateStart,
      govAgeAbsent: record.govAgeAbsent,
      govAgePlus: record.govAgePlus,
      reasonSameDate: record.reasonSameDate,
    };

    return new HttpSuccess(data);
  }

  /**
   *
   * @summary ข้อมูลราชการ
   *
   */
  @Get("{profileEmployeeId}")
  @Example({})
  public async getGovHistory(@Path() profileEmployeeId: string, @Request() req: RequestWithUser) {
    let _workflow = await new permission().Workflow(req, profileEmployeeId, "SYS_REGISTRY_EMP");
    if (_workflow == false)
      await new permission().PermissionOrgUserGet(req, "SYS_REGISTRY_EMP", profileEmployeeId);
    const orgRevision = await this.orgRevisionRepository.findOne({
      select: ["id"],
      where: {
        orgRevisionIsDraft: false,
        orgRevisionIsCurrent: true,
      },
    });

    // ค้นหา profile ก่อน
    const record = await this.profileEmployeeRepo.findOne({
      where: { id: profileEmployeeId },
      relations: ["posType", "posLevel"],
    });

    if (!record) {
      throw new HttpError(HttpStatus.NOT_FOUND, "ไม่พบข้อมูล profile");
    }
    const posMaster = await this.posMasterRepo.findOne({
      where: {
        orgRevisionId: orgRevision?.id,
        current_holderId: profileEmployeeId,
      },
      order: { createdAt: "DESC" },
      relations: {
        orgRoot: true,
        orgChild1: true,
        orgChild2: true,
        orgChild3: true,
        orgChild4: true,
      },
    });

    // if (!record) throw new HttpError(HttpStatus.NOT_FOUND, "ไม่พบข้อมูล");
    const fullNameParts = [
      posMaster == null || posMaster.orgChild4 == null ? null : posMaster.orgChild4.orgChild4Name,
      posMaster == null || posMaster.orgChild3 == null ? null : posMaster.orgChild3.orgChild3Name,
      posMaster == null || posMaster.orgChild2 == null ? null : posMaster.orgChild2.orgChild2Name,
      posMaster == null || posMaster.orgChild1 == null ? null : posMaster.orgChild1.orgChild1Name,
      posMaster == null || posMaster.orgRoot == null ? null : posMaster.orgRoot.orgRootName,
    ];
    const org = fullNameParts.filter((part) => part !== undefined && part !== null).join("\n");
    let orgShortName = "";
    if (posMaster != null) {
      if (posMaster.orgChild1Id === null) {
        orgShortName = posMaster.orgRoot?.orgRootShortName;
      } else if (posMaster.orgChild2Id === null) {
        orgShortName = posMaster.orgChild1?.orgChild1ShortName;
      } else if (posMaster.orgChild3Id === null) {
        orgShortName = posMaster.orgChild2?.orgChild2ShortName;
      } else if (posMaster.orgChild4Id === null) {
        orgShortName = posMaster.orgChild3?.orgChild3ShortName;
      } else {
        orgShortName = posMaster.orgChild4?.orgChild4ShortName;
      }
    }
    let _OrgLeave: any = [];
    let orgLeave: string = "";
    let posNoLeave: string = "";
    let _profileSalary: any = null;
    if (record?.isLeave /*&& record?.profileSalary.length > 0*/) {
      const profileSalary = await this.salaryRepo.find({
        select: [
          "orgRoot",
          "orgChild1",
          "orgChild2",
          "orgChild3",
          "orgChild4",
          "posNoAbb",
          "posNo",
        ],
        where: {
          profileEmployeeId: profileEmployeeId,
          commandCode: In([
            "0",
            "9",
            "1",
            "2",
            "3",
            "4",
            "8",
            "10",
            "11",
            "12",
            "13",
            "14",
            "15",
            "16",
            "20",
          ]),
        },
        order: {
          order: "DESC",
          createdAt: "DESC",
        },
      });
      // _OrgLeave = [
      //   profileSalary.length > 0 && profileSalary[0].orgChild4 ? profileSalary[0].orgChild4 : null,
      //   profileSalary.length > 0 && profileSalary[0].orgChild3 ? profileSalary[0].orgChild3 : null,
      //   profileSalary.length > 0 && profileSalary[0].orgChild2 ? profileSalary[0].orgChild2 : null,
      //   profileSalary.length > 0 && profileSalary[0].orgChild1 ? profileSalary[0].orgChild1 : null,
      //   profileSalary.length > 0 && profileSalary[0].orgRoot ? profileSalary[0].orgRoot : null,
      // ];
      if (record.leaveType == "RETIRE") {
        _profileSalary =
          profileSalary.length > 1
            ? profileSalary[1]
            : profileSalary.length > 0
              ? profileSalary[0]
              : null;
      } else {
        _profileSalary = profileSalary.length > 0 ? profileSalary[0] : null;
      }
      if (_profileSalary) {
        _OrgLeave = [
          _profileSalary.orgChild4 ?? null,
          _profileSalary.orgChild3 ?? null,
          _profileSalary.orgChild2 ?? null,
          _profileSalary.orgChild1 ?? null,
          _profileSalary.orgRoot ?? null,
        ];
      } else {
        _OrgLeave = [];
      }
      orgLeave = _OrgLeave.filter((x: any) => x !== undefined && x !== null).join("\n");
      posNoLeave =
        _profileSalary != null ? `${_profileSalary.posNoAbb} ${_profileSalary.posNo}` : "";
    }
    const data = {
      org: record?.isLeave == false ? org : orgLeave, //สังกัด
      position: record?.position, //ตำแหน่ง
      posLevel:
        record?.posLevel == null
          ? null
          : `${record?.posType?.posTypeShortName ?? ""} ${record?.posLevel?.posLevelName ?? ""}`, //ระดับ
      posMasterNo:
        record?.isLeave == false
          ? posMaster == null
            ? null
            : `${orgShortName} ${[posMaster.posMasterNoPrefix, posMaster.posMasterNo, posMaster.posMasterNoSuffix].filter((p) => p !== null && p !== undefined && p !== '').join(' ')}`
          : posNoLeave /*record && record?.profileSalary.length > 0
          ? `${record?.profileSalary[0].posNoAbb} ${record?.profileSalary[0].posNo}`
          : null*/, //เลขที่ตำแหน่ง
      posType: record?.posType == null ? null : record?.posType.posTypeName, //ประเภท
      dateLeave: record?.birthDate == null ? null : calculateRetireDate(record?.birthDate), //วันเกษียณ
      dateAppoint: record?.dateAppoint, //วันที่สั่งบรรจุ
      dateStart: record?.dateStart, //วันที่เริ่มปฎิบัติงานราชการ
      reasonSameDate: record?.reasonSameDate, //เหตุผลที่วันที่ไม่ตรงกัน
      dateRetire: record?.dateRetire ?? null, //วันครบเกษียณอายุ
      // govAge: record?.dateStart == null ? null : calculateAge(record?.dateStart), //อายุราชการ
      govAge: await calculateGovAge(profileEmployeeId, "EMPLOYEE"),
      govAgeBkk: await calculateGovAge(profileEmployeeId, "EMPLOYEE", true),
      govAgeAbsent: record?.govAgeAbsent ?? null, // ขาดราชการ
      govAgePlus: record?.govAgePlus, // อายุราชการเกื้อกูล
      dateRetireLaw: record?.dateRetireLaw ?? null, // วันที่เกษียฯอายุราชการตามกฎหมาย
    };
    return new HttpSuccess(data);
  }

  @Get("admin/{profileEmployeeId}")
  public async getGovHistoryAdmin(@Path() profileEmployeeId: string) {
    const orgRevision = await this.orgRevisionRepository.findOne({
      select: ["id"],
      where: {
        orgRevisionIsDraft: false,
        orgRevisionIsCurrent: true,
      },
    });

    // ค้นหา profile ก่อน
    const record = await this.profileEmployeeRepo.findOne({
      where: { id: profileEmployeeId },
      relations: ["posType", "posLevel"],
    });

    if (!record) {
      throw new HttpError(HttpStatus.NOT_FOUND, "ไม่พบข้อมูล profile");
    }
    const posMaster = await this.posMasterRepo.findOne({
      where: {
        orgRevisionId: orgRevision?.id,
        current_holderId: profileEmployeeId,
      },
      order: { createdAt: "DESC" },
      relations: {
        orgRoot: true,
        orgChild1: true,
        orgChild2: true,
        orgChild3: true,
        orgChild4: true,
      },
    });

    // if (!record) throw new HttpError(HttpStatus.NOT_FOUND, "ไม่พบข้อมูล");
    const fullNameParts = [
      posMaster == null || posMaster.orgChild4 == null ? null : posMaster.orgChild4.orgChild4Name,
      posMaster == null || posMaster.orgChild3 == null ? null : posMaster.orgChild3.orgChild3Name,
      posMaster == null || posMaster.orgChild2 == null ? null : posMaster.orgChild2.orgChild2Name,
      posMaster == null || posMaster.orgChild1 == null ? null : posMaster.orgChild1.orgChild1Name,
      posMaster == null || posMaster.orgRoot == null ? null : posMaster.orgRoot.orgRootName,
    ];
    const org = fullNameParts.filter((part) => part !== undefined && part !== null).join("\n");
    let orgShortName = "";
    if (posMaster != null) {
      if (posMaster.orgChild1Id === null) {
        orgShortName = posMaster.orgRoot?.orgRootShortName;
      } else if (posMaster.orgChild2Id === null) {
        orgShortName = posMaster.orgChild1?.orgChild1ShortName;
      } else if (posMaster.orgChild3Id === null) {
        orgShortName = posMaster.orgChild2?.orgChild2ShortName;
      } else if (posMaster.orgChild4Id === null) {
        orgShortName = posMaster.orgChild3?.orgChild3ShortName;
      } else {
        orgShortName = posMaster.orgChild4?.orgChild4ShortName;
      }
    }
    let _OrgLeave: any = [];
    let orgLeave: string = "";
    let posNoLeave: string = "";
    let _profileSalary: any = null;
    if (record?.isLeave /*&& record?.profileSalary.length > 0*/) {
      const profileSalary = await this.salaryRepo.find({
        select: [
          "orgRoot",
          "orgChild1",
          "orgChild2",
          "orgChild3",
          "orgChild4",
          "posNoAbb",
          "posNo",
        ],
        where: {
          profileEmployeeId: profileEmployeeId,
          commandCode: In([
            "0",
            "9",
            "1",
            "2",
            "3",
            "4",
            "8",
            "10",
            "11",
            "12",
            "13",
            "14",
            "15",
            "16",
            "20",
          ]),
        },
        order: {
          order: "DESC",
          createdAt: "DESC",
        },
      });
      // _OrgLeave = [
      //   profileSalary.length > 0 && profileSalary[0].orgChild4 ? profileSalary[0].orgChild4 : null,
      //   profileSalary.length > 0 && profileSalary[0].orgChild3 ? profileSalary[0].orgChild3 : null,
      //   profileSalary.length > 0 && profileSalary[0].orgChild2 ? profileSalary[0].orgChild2 : null,
      //   profileSalary.length > 0 && profileSalary[0].orgChild1 ? profileSalary[0].orgChild1 : null,
      //   profileSalary.length > 0 && profileSalary[0].orgRoot ? profileSalary[0].orgRoot : null,
      // ];
      if (record.leaveType == "RETIRE") {
        _profileSalary =
          profileSalary.length > 1
            ? profileSalary[1]
            : profileSalary.length > 0
              ? profileSalary[0]
              : null;
      } else {
        _profileSalary = profileSalary.length > 0 ? profileSalary[0] : null;
      }
      if (_profileSalary) {
        _OrgLeave = [
          _profileSalary.orgChild4 ?? null,
          _profileSalary.orgChild3 ?? null,
          _profileSalary.orgChild2 ?? null,
          _profileSalary.orgChild1 ?? null,
          _profileSalary.orgRoot ?? null,
        ];
      } else {
        _OrgLeave = [];
      }
      orgLeave = _OrgLeave.filter((x: any) => x !== undefined && x !== null).join("\n");
      posNoLeave =
        _profileSalary != null ? `${_profileSalary.posNoAbb} ${_profileSalary.posNo}` : "";
    }
    const data = {
      org: record?.isLeave == false ? org : orgLeave, //สังกัด
      position: record?.position, //ตำแหน่ง
      posLevel:
        record?.posLevel == null && record?.posType == null
          ? null
          : `${record?.posType.posTypeShortName} ${record?.posLevel.posLevelName}`, //ระดับ
      posMasterNo:
        record?.isLeave == false
          ? posMaster == null
            ? null
            : `${orgShortName} ${[posMaster.posMasterNoPrefix, posMaster.posMasterNo, posMaster.posMasterNoSuffix].filter((p) => p !== null && p !== undefined && p !== '').join(' ')}`
          : posNoLeave /*record && record.profileSalary.length > 0
            ? `${record?.profileSalary[0].posNoAbb} ${record?.profileSalary[0].posNo}`
            : null*/, //เลขที่ตำแหน่ง
      posType: record?.posType == null ? null : record?.posType.posTypeName, //ประเภท
      dateLeave: record?.birthDate == null ? null : calculateRetireDate(record?.birthDate), //วันเกษียณ
      dateAppoint: record?.dateAppoint, //วันที่สั่งบรรจุ
      dateStart: record?.dateStart, //วันที่เริ่มปฎิบัติงานราชการ
      reasonSameDate: record?.reasonSameDate, //เหตุผลที่วันที่ไม่ตรงกัน
      dateRetire: record?.dateRetire ?? null, //วันครบเกษียณอายุ
      // govAge: record?.dateStart == null ? null : calculateAge(record?.dateStart), //อายุราชการ
      govAge: await calculateGovAge(profileEmployeeId, "EMPLOYEE"),
      govAgeBkk: await calculateGovAge(profileEmployeeId, "EMPLOYEE", true),
      govAgeAbsent: record?.govAgeAbsent ?? null, // ขาดราชการ
      govAgePlus: record?.govAgePlus, // อายุราชการเกื้อกูล
      dateRetireLaw: record?.dateRetireLaw ?? null, // วันที่เกษียฯอายุราชการตามกฎหมาย
      isLeave: record?.isLeave,
    };
    return new HttpSuccess(data);
  }

  /**
   *
   * @summary ประวัติข้อมูลราชการ by keycloak
   *
   */
  @Get("history/user")
  public async govHistoryUser(@Request() request: RequestWithUser) {
    const profile = await this.profileEmployeeRepo.findOneBy({ keycloak: request.user.sub });
    if (!profile) {
      throw new HttpError(HttpStatus.BAD_REQUEST, "ไม่พบ profile ดังกล่าว");
    }
    const record = await this.govRepo.find({
      order: { lastUpdatedAt: "DESC" },
      where: { profileEmployeeId: profile.id },
    });
    return new HttpSuccess(record);
  }

  /**
   *
   * @summary ประวัติข้อมูลราชการ
   *
   */
  @Get("history/{profileEmployeeId}")
  @Example({})
  public async govHistory(@Path() profileEmployeeId: string, @Request() req: RequestWithUser) {
    let _workflow = await new permission().Workflow(req, profileEmployeeId, "SYS_REGISTRY_EMP");
    if (_workflow == false)
      await new permission().PermissionOrgUserGet(req, "SYS_REGISTRY_EMP", profileEmployeeId);
    const record = await this.govRepo.find({
      order: { lastUpdatedAt: "DESC" },
      where: { profileEmployeeId: profileEmployeeId },
    });
    return new HttpSuccess(record);
  }

  /**
   *
   * @summary แก้ไขข้อมูลราชการ
   *
   */
  @Patch("{profileEmployeeId}")
  public async editGov(
    @Request() req: RequestWithUser,
    @Body() body: UpdateProfileGovernment,
    @Path() profileEmployeeId: string,
  ) {
    await new permission().PermissionOrgUserUpdate(req, "SYS_REGISTRY_EMP", profileEmployeeId);
    const record = await this.profileEmployeeRepo.findOne({
      where: { id: profileEmployeeId },
    });

    if (!record) throw new HttpError(HttpStatus.NOT_FOUND, "ไม่พบข้อมูล");
    const before = structuredClone(record);
    const history = new ProfileGovernment();

    Object.assign(record, body);
    Object.assign(history, { ...record, id: undefined });

    history.profileEmployeeId = profileEmployeeId;
    record.lastUpdateUserId = req.user.sub;
    record.lastUpdateFullName = req.user.name;
    record.lastUpdatedAt = new Date();
    history.lastUpdateUserId = req.user.sub;
    history.lastUpdateFullName = req.user.name;
    history.createdUserId = req.user.sub;
    history.createdFullName = req.user.name;
    history.createdAt = new Date();
    history.lastUpdatedAt = new Date();

    await Promise.all([
      this.profileEmployeeRepo.save(record, { data: req }),
      setLogDataDiff(req, { before, after: record }),
      this.govRepo.save(history, { data: req }),
    ]);
    return new HttpSuccess();
  }
}
