import {
  Controller,
  Get,
  Post,
  Put,
  Delete,
  Route,
  Security,
  Tags,
  Body,
  Path,
  Request,
  Response,
  Query,
} from "tsoa";
import { AppDataSource } from "../database/data-source";
import HttpSuccess from "../interfaces/http-success";
import HttpStatusCode from "../interfaces/http-status";
import HttpError from "../interfaces/http-error";
import { In, Not, Brackets } from "typeorm";
import { RequestWithUser } from "../middlewares/user";
import {
  ChangePosition,
  CreateChangePosition,
  UpdateChangePosition,
} from "../entities/ChangePosition";
import {
  ProfileChangePosition,
  CreateProfileChangePosition,
  UpdateProfileChangePosition,
  SelectProfileChangePosition,
} from "../entities/ProfileChangePosition";
import { OrgRoot } from "../entities/OrgRoot";
import { OrgChild1 } from "../entities/OrgChild1";
import { OrgChild2 } from "../entities/OrgChild2";
import { OrgChild3 } from "../entities/OrgChild3";
import { OrgChild4 } from "../entities/OrgChild4";
import CallAPI from "../interfaces/call-api";
@Route("api/v1/org/placement/change-position")
@Tags("Placement")
@Security("bearerAuth")
@Response(
  HttpStatusCode.INTERNAL_SERVER_ERROR,
  "เกิดข้อผิดพลาด ไม่สามารถแสดงรายการได้ กรุณาลองใหม่ในภายหลัง",
)
export class ChangePositionController extends Controller {
  private changePositionRepository = AppDataSource.getRepository(ChangePosition);
  private profileChangePositionRepository = AppDataSource.getRepository(ProfileChangePosition);
  private orgRootRepository = AppDataSource.getRepository(OrgRoot);
  private child1Repository = AppDataSource.getRepository(OrgChild1);
  private child2Repository = AppDataSource.getRepository(OrgChild2);
  private child3Repository = AppDataSource.getRepository(OrgChild3);
  private child4Repository = AppDataSource.getRepository(OrgChild4);

  /**
   * API เพิ่มรอบย้ายสับเปลี่ยนตำแหน่ง
   *
   * @summary เพิ่มรอบย้ายสับเปลี่ยนตำแหน่ง (ADMIN)
   *
   */
  @Post()
  async CreateChangePosition(
    @Body() body: CreateChangePosition,
    @Request() request: RequestWithUser,
  ) {
    const _changePosition = await this.changePositionRepository.findOne({
      where: { name: body.name },
    });
    if (_changePosition) {
      throw new HttpError(
        HttpStatusCode.INTERNAL_SERVER_ERROR,
        "ชื่อรอบการย้ายสับเปลี่ยนตำแหน่งนี้มีอยู่ในระบบแล้ว",
      );
    }

    const changePosition = new ChangePosition();
    Object.assign(changePosition, body);
    changePosition.date = new Date();
    changePosition.status = "WAITTING";
    changePosition.createdUserId = request.user.sub;
    changePosition.createdFullName = request.user.name;
    changePosition.createdAt = new Date();
    changePosition.lastUpdateUserId = request.user.sub;
    changePosition.lastUpdateFullName = request.user.name;
    changePosition.lastUpdatedAt = new Date();
    await this.changePositionRepository.save(changePosition);
    return new HttpSuccess();
  }

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

  /**
   * API แก้ไขรอบย้ายสับเปลี่ยนตำแหน่ง
   *
   * @summary แก้ไขรอบย้ายสับเปลี่ยนตำแหน่ง (ADMIN)
   *
   * @param {string} id  Id รอบย้ายสับเปลี่ยนตำแหน่ง
   */
  @Put("{id}")
  async UpdateChangePosition(
    @Request() request: RequestWithUser,
    @Path() id: string,
    @Body() body: UpdateChangePosition,
  ) {
    const changePosition = await this.changePositionRepository.findOneBy({ id });
    if (!changePosition)
      throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูลรอบย้ายสับเปลี่ยนตำแหน่ง");

    const checkDuplicate = await this.changePositionRepository.find({
      where: {
        id: Not(id),
        name: body.name,
      },
    });
    if (checkDuplicate.length > 0) {
      throw new HttpError(
        HttpStatusCode.INTERNAL_SERVER_ERROR,
        "ชื่อรอบการย้ายสับเปลี่ยนตำแหน่งนี้มีอยู่ในระบบแล้ว",
      );
    }
    Object.assign(changePosition, body);
    changePosition.lastUpdateUserId = request.user.sub;
    changePosition.lastUpdateFullName = request.user.name;
    changePosition.lastUpdatedAt = new Date();
    await this.changePositionRepository.save(changePosition);
    return new HttpSuccess();
  }

  /**
   * API รายการรอบย้ายสับเปลี่ยนตำแหน่ง
   *
   * @summary API รายการรอบย้ายสับเปลี่ยนตำแหน่ง (ADMIN)
   *
   */
  @Get()
  async GetChangePositionLists(
    @Query("page") page: number = 1,
    @Query("pageSize") pageSize: number = 10,
    @Query() searchKeyword: string = "",
  ) {
    const [changePosition, total] = await AppDataSource.getRepository(ChangePosition)
      .createQueryBuilder("changePosition")
      .leftJoinAndSelect("changePosition.profileChangePosition", "profileChangePosition")
      .where(
        searchKeyword
          ? "changePosition.name LIKE :keyword OR changePosition.date LIKE :keyword OR changePosition.status LIKE :keyword"
          : "1=1",
        { keyword: `%${searchKeyword}%` },
      )
      .orderBy("changePosition.date", "ASC")
      .skip((page - 1) * pageSize)
      .take(pageSize)
      .getManyAndCount();

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

  /**
   * API รายการรายชื่อผู้ที่ย้ายสับเปลี่ยนตำแหน่ง สถานะเลือกตำแหน่งแล้ว
   *
   * @summary รายการรายชื่อผู้ที่ย้ายสับเปลี่ยนตำแหน่ง สถานะเลือกตำแหน่งแล้ว (ADMIN)
   *
   */
  @Get("pending")
  async getProfilePending() {
    const profiles = await this.changePositionRepository.find({
      relations: ["profileChangePosition"],
      where: {
        profileChangePosition: {
          status: "PENDING",
        },
      },
    });
    return new HttpSuccess(profiles);
  }

  /**
   * API รายละเอียดรอบย้ายสับเปลี่ยนตำแหน่ง
   *
   * @summary API รายละเอียดรอบย้ายสับเปลี่ยนตำแหน่ง (ADMIN)
   *
   * @param {string} id  Id รอบย้ายสับเปลี่ยนตำแหน่ง
   */
  @Get("{id}")
  async GetChangePositionById(@Path() id: string) {
    const data = await this.changePositionRepository.findOne({
      relations: ["profileChangePosition"],
      where: { id: id },
    });
    if (!data) throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูลรอบย้ายสับเปลี่ยนตำแหน่ง");
    return new HttpSuccess(data);
  }

  /**
   * API เพิ่มเพิ่มรายชื่อผู้ที่ย้ายสับเปลี่ยนตำแหน่ง
   *
   * @summary เพิ่มเพิ่มรายชื่อผู้ที่ย้ายสับเปลี่ยนตำแหน่ง (ADMIN)
   *
   * @param {string} changePositionId  changePositionId รอบย้ายสับเปลี่ยนตำแหน่ง
   */
  @Post("profile/{changePositionId}")
  async CreateProfileChangePosition(
    @Path() changePositionId: string,
    @Body() body: CreateProfileChangePosition,
    @Request() request: RequestWithUser,
  ) {
    const changePosition = await this.changePositionRepository.findOneBy({ id: changePositionId });
    if (!changePosition)
      throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูลรอบย้ายสับเปลี่ยนตำแหน่ง");

    const profileChangePositions: ProfileChangePosition[] = [];
    const profiles = new ProfileChangePosition();
    for (const data of body.profiles) {
      Object.assign(profiles, data);
      let positionOld = data.positionOld ? `${data.positionOld}` : "";
      let rootOld = data.rootOld ? (data.positionOld ? `/${data.rootOld}` : `${data.rootOld}`) : "";
      profiles.changePositionId = changePositionId;
      profiles.organizationPositionOld = `${positionOld}${rootOld}`;
      profiles.status = "WAITTING";
      profiles.createdUserId = request.user.sub;
      profiles.createdFullName = request.user.name;
      profiles.createdAt = new Date();
      profiles.lastUpdateUserId = request.user.sub;
      profiles.lastUpdateFullName = request.user.name;
      profiles.lastUpdatedAt = new Date();
      profileChangePositions.push(profiles);
    }
    await this.profileChangePositionRepository.save(profileChangePositions);
    return new HttpSuccess();
  }

  /**
   * API ลบรายชื่อผู้ที่ย้ายสับเปลี่ยนตำแหน่ง
   *
   * @summary ลบรายชื่อผู้ที่ย้ายสับเปลี่ยนตำแหน่ง (ADMIN)
   *
   * @param {string} id  Id รายชื่อผู้ที่ย้ายสับเปลี่ยนตำแหน่ง
   */
  @Delete("profile/{id}")
  async DeleteProfileChangePosition(@Path() id: string) {
    const result = await this.profileChangePositionRepository.delete({ id: id });
    if (result.affected == undefined || result.affected <= 0) {
      throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูล");
    }
    return new HttpSuccess();
  }

  /**
   * API รายการรายชื่อผู้ที่ย้ายสับเปลี่ยนตำแหน่ง
   *
   * @summary API รายการรายชื่อผู้ที่ย้ายสับเปลี่ยนตำแหน่ง (ADMIN)
   *
   * @param {string} changePositionId  Id รอบย้ายสับเปลี่ยนตำแหน่ง
   */
  @Get("profile-all/{changePositionId}")
  async GetProfileChangePositionLists(
    @Path() changePositionId: string,
    @Query("page") page: number = 1,
    @Query("pageSize") pageSize: number = 10,
    @Query() searchKeyword: string = "",
  ) {
    const [profileChangePosition, total] = await AppDataSource.getRepository(ProfileChangePosition)
      .createQueryBuilder("profileChangePosition")
      .where({ changePositionId: changePositionId })
      .andWhere(
        new Brackets((qb) => {
          qb.where(
            searchKeyword != undefined && searchKeyword != null && searchKeyword != ""
              ? "profileChangePosition.prefix LIKE :keyword"
              : "1=1",
            {
              keyword: `%${searchKeyword}%`,
            },
          )
            .orWhere(
              searchKeyword != undefined && searchKeyword != null && searchKeyword != ""
                ? "profileChangePosition.firstName LIKE :keyword"
                : "1=1",
              {
                keyword: `%${searchKeyword}%`,
              },
            )
            .orWhere(
              searchKeyword != undefined && searchKeyword != null && searchKeyword != ""
                ? "profileChangePosition.lastName LIKE :keyword"
                : "1=1",
              {
                keyword: `%${searchKeyword}%`,
              },
            )
            .orWhere(
              searchKeyword != undefined && searchKeyword != null && searchKeyword != ""
                ? "profileChangePosition.citizenId LIKE :keyword"
                : "1=1",
              {
                keyword: `%${searchKeyword}%`,
              },
            )
            .orWhere(
              searchKeyword != undefined && searchKeyword != null && searchKeyword != ""
                ? "profileChangePosition.birthDate LIKE :keyword"
                : "1=1",
              {
                keyword: `%${searchKeyword}%`,
              },
            )
            .orWhere(
              searchKeyword != undefined && searchKeyword != null && searchKeyword != ""
                ? "profileChangePosition.lastUpdatedAt LIKE :keyword"
                : "1=1",
              {
                keyword: `%${searchKeyword}%`,
              },
            )
            .orWhere(
              searchKeyword != undefined && searchKeyword != null && searchKeyword != ""
                ? "profileChangePosition.status LIKE :keyword"
                : "1=1",
              {
                keyword: `%${searchKeyword}%`,
              },
            );
        }),
      )
      .orderBy("profileChangePosition.createdAt", "ASC")
      .skip((page - 1) * pageSize)
      .take(pageSize)
      .getManyAndCount();

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

  /**
   * API รายละเอียดรายชื่อผู้ที่ย้ายสับเปลี่ยนตำแหน่ง
   *
   * @summary API รายละเอียดรายชื่อผู้ที่ย้ายสับเปลี่ยนตำแหน่ง (ADMIN)
   *
   * @param {string} id  Id รายชื่อผู้ที่ย้ายสับเปลี่ยนตำแหน่ง
   */
  @Get("profile/{id}")
  async GetProfileChangePositionById(@Path() id: string) {
    const profileChangePos = await this.profileChangePositionRepository.findOne({
      where: { id: id },
    });
    if (!profileChangePos)
      throw new HttpError(
        HttpStatusCode.NOT_FOUND,
        "ไม่พบข้อมูลรายชื่อผู้ที่ย้ายสับเปลี่ยนตำแหน่ง",
      );
    return new HttpSuccess(profileChangePos);
  }

  /**
   * API แก้ไขข้อมูลเพื่อลงบัญชีแนบท้าย
   *
   * @summary แก้ไขข้อมูลเพื่อลงบัญชีแนบท้าย (ADMIN)
   *
   * @param {string} id  Id รายชื่อผู้ที่ย้ายสับเปลี่ยนตำแหน่ง
   */
  @Put("profile/{id}")
  async UpdateProfileChangePositionById(
    @Request() request: RequestWithUser,
    @Path() id: string,
    @Body() body: UpdateProfileChangePosition,
  ) {
    const profileChangePos = await this.profileChangePositionRepository.findOneBy({ id });
    if (!profileChangePos)
      throw new HttpError(
        HttpStatusCode.NOT_FOUND,
        "ไม่พบข้อมูลรายชื่อผู้ที่ย้ายสับเปลี่ยนตำแหน่งนี้",
      );

    profileChangePos.lastUpdateUserId = request.user.sub;
    profileChangePos.lastUpdateFullName = request.user.name;
    profileChangePos.lastUpdatedAt = new Date();
    profileChangePos.educationOld = body.educationOld;
    profileChangePos.posMasterNoOld = body.posMasterNoOld;
    profileChangePos.positionTypeOld = body.positionTypeOld;
    profileChangePos.positionLevelOld = body.positionLevelOld;
    profileChangePos.organizationPositionOld = body.organizationPositionOld;
    profileChangePos.amountOld = body.amountOld;
    profileChangePos.reason = body.reason ? String(body.reason) : "";
    profileChangePos.dateCurrent = body.dateCurrent;
    await this.profileChangePositionRepository.save(profileChangePos);
    return new HttpSuccess();
  }

  /**
   * API บันทึก เลือกหน่วยงานที่รับย้าย
   *
   * @summary บันทึก เลือกหน่วยงานที่รับย้าย (ADMIN)
   *
   * @param {string} id  Id รายชื่อผู้ที่ย้ายสับเปลี่ยนตำแหน่ง
   */
  @Put("profile/position/{id}")
  async positionProfileEmployee(
    @Request() request: RequestWithUser,
    @Path() id: string,
    @Body() body: SelectProfileChangePosition,
  ) {
    const profileChangePos = await this.profileChangePositionRepository.findOneBy({ id });
    if (!profileChangePos)
      throw new HttpError(
        HttpStatusCode.NOT_FOUND,
        "ไม่พบข้อมูลรายชื่อผู้ที่ย้ายสับเปลี่ยนตำแหน่งนี้",
      );

    switch (body.node) {
      case 0: {
        const data = await this.orgRootRepository.findOne({
          where: { id: body.nodeId },
        });
        if (data != null) {
          profileChangePos.rootId = data.id;
          profileChangePos.root = data.orgRootName;
          profileChangePos.rootShortName = data.orgRootShortName;
        }
      }
      case 1: {
        const data = await this.child1Repository.findOne({
          where: { id: body.nodeId },
          relations: ["orgRoot"],
        });
        if (data != null) {
          profileChangePos.rootId = data.orgRoot.id;
          profileChangePos.root = data.orgRoot.orgRootName;
          profileChangePos.rootShortName = data.orgRoot.orgRootShortName;
          profileChangePos.child1Id = data.id;
          profileChangePos.child1 = data.orgChild1Name;
          profileChangePos.child1ShortName = data.orgChild1ShortName;
        }
      }
      case 2: {
        const data = await this.child2Repository.findOne({
          where: { id: body.nodeId },
          relations: ["orgRoot", "orgChild1"],
        });
        if (data != null) {
          profileChangePos.rootId = data.orgRoot.id;
          profileChangePos.root = data.orgRoot.orgRootName;
          profileChangePos.rootShortName = data.orgRoot.orgRootShortName;
          profileChangePos.child1Id = data.orgChild1.id;
          profileChangePos.child1 = data.orgChild1.orgChild1Name;
          profileChangePos.child1ShortName = data.orgChild1.orgChild1ShortName;
          profileChangePos.child2Id = data.id;
          profileChangePos.child2 = data.orgChild2Name;
          profileChangePos.child2ShortName = data.orgChild2ShortName;
        }
      }
      case 3: {
        const data = await this.child3Repository.findOne({
          where: { id: body.nodeId },
          relations: ["orgRoot", "orgChild1", "orgChild2"],
        });
        if (data != null) {
          profileChangePos.rootId = data.orgRoot.id;
          profileChangePos.root = data.orgRoot.orgRootName;
          profileChangePos.rootShortName = data.orgRoot.orgRootShortName;
          profileChangePos.child1Id = data.orgChild1.id;
          profileChangePos.child1 = data.orgChild1.orgChild1Name;
          profileChangePos.child1ShortName = data.orgChild1.orgChild1ShortName;
          profileChangePos.child2Id = data.orgChild2.id;
          profileChangePos.child2 = data.orgChild2.orgChild2Name;
          profileChangePos.child2ShortName = data.orgChild2.orgChild2ShortName;
          profileChangePos.child3Id = data.id;
          profileChangePos.child3 = data.orgChild3Name;
          profileChangePos.child3ShortName = data.orgChild3ShortName;
        }
      }
      case 4: {
        const data = await this.child4Repository.findOne({
          where: { id: body.nodeId },
          relations: ["orgRoot", "orgChild1", "orgChild2", "orgChild3"],
        });
        if (data != null) {
          profileChangePos.rootId = data.orgRoot.id;
          profileChangePos.root = data.orgRoot.orgRootName;
          profileChangePos.rootShortName = data.orgRoot.orgRootShortName;
          profileChangePos.child1Id = data.orgChild1.id;
          profileChangePos.child1 = data.orgChild1.orgChild1Name;
          profileChangePos.child1ShortName = data.orgChild1.orgChild1ShortName;
          profileChangePos.child2Id = data.orgChild2.id;
          profileChangePos.child2 = data.orgChild2.orgChild2Name;
          profileChangePos.child2ShortName = data.orgChild2.orgChild2ShortName;
          profileChangePos.child3Id = data.orgChild3.id;
          profileChangePos.child3 = data.orgChild3.orgChild3Name;
          profileChangePos.child3ShortName = data.orgChild3.orgChild3ShortName;
          profileChangePos.child4Id = data.id;
          profileChangePos.child4 = data.orgChild4Name;
          profileChangePos.child4ShortName = data.orgChild4ShortName;
        }
      }
    }

    profileChangePos.lastUpdateUserId = request.user.sub;
    profileChangePos.lastUpdateFullName = request.user.name;
    profileChangePos.lastUpdatedAt = new Date();
    profileChangePos.node = body.node;
    profileChangePos.nodeId = body.nodeId;
    profileChangePos.orgRevisionId = body.orgRevisionId;
    profileChangePos.posmasterId = body.posmasterId;
    profileChangePos.posMasterNo = body.posMasterNo;
    profileChangePos.positionId = body.positionId;
    profileChangePos.position = body.position;
    profileChangePos.positionField = body.positionField;
    profileChangePos.posTypeId = String(body.posTypeId);
    profileChangePos.posTypeName = body.posTypeName;
    profileChangePos.posLevelId = String(body.posLevelId);
    profileChangePos.posLevelName = body.posLevelName;
    profileChangePos.status = "PENDING";
    await this.profileChangePositionRepository.save(profileChangePos);
    return new HttpSuccess();
  }

  /**
   * API ออกคำสั่งย้ายสับเปลี่ยนตำแหน่ง REPORT
   *
   * @summary API ออกคำสั่งย้ายสับเปลี่ยนตำแหน่ง REPORT (ADMIN)
   *
   */
  @Post("report")
  async sendReport(@Request() request: RequestWithUser, @Body() requestBody: { id: string[] }) {
    const profilechangePositions = await this.changePositionRepository.find({
      relations: ["profileChangePosition"],
      where: { id: In(requestBody.id) },
    });

    for (const item of profilechangePositions) {
      item.status = "REPORT";
      item.lastUpdateUserId = request.user.sub;
      item.lastUpdateFullName = request.user.name;
      item.lastUpdatedAt = new Date();
      if (item.profileChangePosition) {
        for (const profile of item.profileChangePosition) {
          profile.status = "REPORT";
          profile.lastUpdateUserId = request.user.sub;
          profile.lastUpdateFullName = request.user.name;
          profile.lastUpdatedAt = new Date();
          await this.profileChangePositionRepository.save(profile);
        }
      }
      await this.changePositionRepository.save(item);
    }
    return new HttpSuccess();
  }

  /**
   * API ออกคำสั่งย้ายสับเปลี่ยนตำแหน่ง DONE
   *
   * @summary API ออกคำสั่งย้ายสับเปลี่ยนตำแหน่ง DONE (ADMIN)
   *
   */
  @Post("report/resume")
  async doneReport(
    @Body()
    body: {
      result: {
        id: string;
      }[];
    },
    @Request() request: { user: Record<string, any> },
  ) {
    await Promise.all(
      body.result.map(async (v) => {
        const profile = await this.profileChangePositionRepository.findOne({
          where: { id: v.id },
        });
        if (profile != null) {
          await new CallAPI()
            .PostData(request, "/org/profile/salary", {
              profileId: profile.id,
              date: new Date(),
            })
            .then(async (x) => {
              profile.status = "DONE";
              await this.profileChangePositionRepository.save(profile);
            });
        }
      }),
    );
    return new HttpSuccess();
  }
}
