import {
  Controller,
  Get,
  Post,
  Put,
  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 { Not } from "typeorm";
import {
  EmployeePosType,
  CreateEmployeePosType,
  UpdateEmployeePosType,
} from "../entities/EmployeePosType";
import { EmployeePosLevel } from "../entities/EmployeePosLevel";
import { EmployeePosDict } from "../entities/EmployeePosDict";
import { RequestWithUser } from "../middlewares/user";
import { setLogDataDiff } from "../interfaces/utils";

@Route("api/v1/org/employee/pos/type")
@Tags("EmployeePosType")
@Security("bearerAuth")
@Response(
  HttpStatusCode.INTERNAL_SERVER_ERROR,
  "เกิดข้อผิดพลาด ไม่สามารถแสดงรายการได้ กรุณาลองใหม่ในภายหลัง",
)
export class EmployeePosTypeController extends Controller {
  private employeePosTypeRepository = AppDataSource.getRepository(EmployeePosType);
  /**
   * API เพิ่มกลุ่มงานลูกจ้างประจำ
   *
   * @summary ORG_ - เพิ่มกลุ่มงานลูกจ้างประจำ (ADMIN) #
   *
   */
  @Post()
  async CreateEmpType(
    @Body()
    requestBody: CreateEmployeePosType,
    @Request() request: RequestWithUser,
  ) {
    const EmpPosType = Object.assign(new EmployeePosType(), requestBody);

    const chkEmpPosTypeName = await this.employeePosTypeRepository.findOne({
      where: {
        posTypeName: requestBody.posTypeName,
      },
    });
    if (chkEmpPosTypeName) {
      throw new HttpError(HttpStatusCode.NOT_FOUND, "ชื่อกลุ่มงานลูกจ้างประจำนี้มีอยู่ในระบบแล้ว");
    }

    const posTypeRank = await this.employeePosTypeRepository.findOne({
      where: {
        posTypeRank: requestBody.posTypeRank,
      },
    });
    if (posTypeRank) {
      throw new HttpError(
        HttpStatusCode.NOT_FOUND,
        "ระดับของกลุ่มงานลูกจ้างประจำนี้มีอยู่ในระบบแล้ว",
      );
    }
    const before = null;
    EmpPosType.createdUserId = request.user.sub;
    EmpPosType.createdFullName = request.user.name;
    EmpPosType.lastUpdateUserId = request.user.sub;
    EmpPosType.lastUpdateFullName = request.user.name;
    EmpPosType.createdAt = new Date();
    EmpPosType.lastUpdatedAt = new Date();
    await this.employeePosTypeRepository.save(EmpPosType, { data: request });
    setLogDataDiff(request, { before, after: EmpPosType });
    return new HttpSuccess(EmpPosType.id);
  }

  /**
   * API แก้ไขกลุ่มงานลูกจ้างประจำ
   *
   * @summary ORG_ - แก้ไขกลุ่มงานลูกจ้างประจำ (ADMIN) #
   *
   * @param {string} id  Id กลุ่มงานลูกจ้างประจำ
   */
  @Put("{id}")
  async EditEmpType(
    @Path() id: string,
    @Body() requestBody: UpdateEmployeePosType,
    @Request() request: RequestWithUser,
  ) {
    const EmpPosType = await this.employeePosTypeRepository.findOne({ where: { id } });
    if (!EmpPosType) {
      throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูลกลุ่มงานลูกจ้างประจำนี้");
    }
    const chkEmpPosType = await this.employeePosTypeRepository.findOne({
      where: {
        id: Not(id),
        posTypeName: requestBody.posTypeName,
      },
    });
    if (chkEmpPosType) {
      throw new HttpError(HttpStatusCode.NOT_FOUND, "ชื่อกลุ่มงานลูกจ้างประจำนี้มีอยู่ในระบบแล้ว");
    }
    const posTypeRank = await this.employeePosTypeRepository.findOne({
      where: {
        id: Not(id),
        posTypeRank: requestBody.posTypeRank,
      },
    });
    if (posTypeRank) {
      throw new HttpError(
        HttpStatusCode.NOT_FOUND,
        "ระดับของกลุ่มงานลูกจ้างประจำนี้มีอยู่ในระบบแล้ว",
      );
    }
    const before = structuredClone(EmpPosType);
    EmpPosType.lastUpdateUserId = request.user.sub;
    EmpPosType.lastUpdateFullName = request.user.name;
    EmpPosType.lastUpdatedAt = new Date();
    this.employeePosTypeRepository.merge(EmpPosType, requestBody);
    await this.employeePosTypeRepository.save(EmpPosType, { data: request });
    setLogDataDiff(request, { before, after: EmpPosType });
    return new HttpSuccess(EmpPosType.id);
  }

  /**
   * API ลบกลุ่มงานลูกจ้างประจำ
   *
   * @summary ORG_ - ลบกลุ่มงานลูกจ้างประจำ (ADMIN) #
   *
   * @param {string} id  Id กลุ่มงานลูกจ้างประจำ
   */
  @Delete("{id}")
  async deleteType(@Path() id: string, @Request() request: RequestWithUser) {
    let result: any;
    try {
      // result = await this.employeePosTypeRepository.findOne({
      //   where: { id: id },
      // });
      // await this.employeePosTypeRepository.remove(result, { data: request });
      result = await this.employeePosTypeRepository.delete({ id: id });
    } catch {
      throw new HttpError(
        HttpStatusCode.NOT_FOUND,
        "ไม่สามารถลบได้เนื่องจากมีการใช้งานระดับกลุ่มงานนี้อยู่",
      );
    }
    if (result.affected == undefined || result.affected <= 0) {
      throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูล");
    }
    // const delEmpPosType = await this.employeePosTypeRepository.findOne({ where: { id } });
    // if (!delEmpPosType) {
    //   throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูลกลุ่มงานลูกจ้างประจำนี้");
    // }
    // // ตารางระดับชั้นงาน
    // const EmpPosLevel = await this.employeePosLevelRepository.find({
    //   where: { posTypeId: id },
    // });
    // if (EmpPosLevel.length > 0) {
    //   throw new HttpError(
    //     HttpStatusCode.NOT_FOUND,
    //     "ไม่สามารถลบข้อมูลได้เนื่องจากมีการใช้งานระดับชั้นงานนี้อยู่",
    //   );
    // }
    // //ตารางตำแหน่งลูกจ้างประจำ
    // const EmpPosition = await this.employeePosDictRepository.find({
    //   where: { posTypeId: id },
    // });
    // if (EmpPosition.length > 0) {
    //   throw new HttpError(
    //     HttpStatusCode.NOT_FOUND,
    //     "ไม่สามารถลบได้เนื่องจากพบข้อมูลที่ตารางตำแหน่งลูกจ้างประจำ",
    //   );
    // }

    // await this.employeePosTypeRepository.remove(delEmpPosType);
    return new HttpSuccess();
  }

  /**
   * API รายละเอียดกลุ่มงานลูกจ้างประจำ
   *
   * @summary ORG_ - รายละเอียดกลุ่มงานลูกจ้างประจำ (ADMIN) #
   *
   * @param {string} id  Id กลุ่มงานลูกจ้างประจำ
   */
  @Get("{id}")
  async GetEmpTypeById(@Path() id: string) {
    const getEmpPosType = await this.employeePosTypeRepository.findOne({
      relations: ["posLevels"],
      select: ["id", "posTypeName", "posTypeRank", "posTypeShortName", "createdAt", "lastUpdatedAt", "lastUpdateFullName"],
      where: { id: id },
      order: {
        posTypeRank: "ASC",
        createdAt: "DESC",
        posLevels: {
          posLevelRank: "ASC",
          createdAt: "DESC"
        }
      }
    });
    if (!getEmpPosType) {
      throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูลกลุ่มงานลูกจ้างประจำนี้");
    }

    const mapGetEmpPosType = {
      id: getEmpPosType.id,
      posTypeName: getEmpPosType.posTypeName,
      posTypeRank: getEmpPosType.posTypeRank,
      posTypeShortName: getEmpPosType.posTypeShortName,
      posLevels: getEmpPosType.posLevels
        .sort((a, b) => a.posLevelRank - b.posLevelRank)
        .map((empPosLevel) => ({
          id: empPosLevel.id,
          posLevelName: empPosLevel.posLevelName,
          posLevelRank: empPosLevel.posLevelRank,
          posLevelAuthority: empPosLevel.posLevelAuthority,
          createdAt: empPosLevel.createdAt,
          lastUpdatedAt: empPosLevel.lastUpdatedAt,
          lastUpdateFullName: empPosLevel.lastUpdateFullName
        })),
      createdAt: getEmpPosType.createdAt,
      lastUpdatedAt: getEmpPosType.lastUpdatedAt,
      lastUpdateFullName: getEmpPosType.lastUpdateFullName
    };

    return new HttpSuccess(mapGetEmpPosType);
  }

  /**
   * API รายการกลุ่มงานลูกจ้างประจำ
   *
   * @summary ORG_ - รายการกลุ่มงานลูกจ้างประจำ (ADMIN) #
   *
   */
  @Get()
  async GetEmpPosType() {
    const empPosType = await this.employeePosTypeRepository.find({
      relations: ["posLevels"],
      select: ["id", "posTypeName", "posTypeRank", "posTypeShortName", "createdAt", "lastUpdatedAt", "lastUpdateFullName"],
      order: { 
        posTypeRank: "ASC",
        createdAt: "DESC",
        posLevels: {
          posLevelRank: "ASC",
          createdAt: "DESC",
        }
      },
    });

    const mapEmpPosType = empPosType.map((item) => ({
      id: item.id,
      posTypeName: item.posTypeName,
      posTypeRank: item.posTypeRank,
      posTypeShortName: item.posTypeShortName,
      posLevels: item.posLevels
        .sort((a, b) => a.posLevelRank - b.posLevelRank)
        .map((empPosLevel) => ({
          id: empPosLevel.id,
          posLevelName: empPosLevel.posLevelName,
          posLevelRank: empPosLevel.posLevelRank,
          posLevelAuthority: empPosLevel.posLevelAuthority,
          createdAt: empPosLevel.createdAt,
          lastUpdatedAt: empPosLevel.lastUpdatedAt,
          lastUpdateFullName: empPosLevel.lastUpdateFullName
        })),
      createdAt: item.createdAt,
      lastUpdatedAt: item.lastUpdatedAt,
      lastUpdateFullName: item.lastUpdateFullName
    }));
    return new HttpSuccess(mapEmpPosType);
  }
}
