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 { InsigniaType } from "../entities/InsigniaType";
import { Insignia, CreateInsignias, UpdateInsignias } from "../entities/Insignia";
import permission from "../interfaces/permission";
import { RequestWithUser } from "../middlewares/user";
@Route("api/v1/org/insignia/insignia")
@Tags("Insignia")
@Security("bearerAuth")
@Response(
  HttpStatusCode.INTERNAL_SERVER_ERROR,
  "เกิดข้อผิดพลาด ไม่สามารถแสดงรายการได้ กรุณาลองใหม่ในภายหลัง",
)
export class InsigniaController extends Controller {
  private insigniaTypeRepository = AppDataSource.getRepository(InsigniaType);
  private insigniaRepository = AppDataSource.getRepository(Insignia);

  /**
   * API เพิ่มข้อมูลเครื่องราชอิสริยาภรณ์
   *
   * @summary ORG_ - เพิ่มข้อมูลเครื่องราชอิสริยาภรณ์ (ADMIN) #
   *
   */
  @Post("")
  async CreateInsignia(
    @Body() requestBody: CreateInsignias,
    @Request() request: { user: Record<string, any> },
  ) {
    const insignia = Object.assign(new Insignia(), requestBody);
    if (!insignia) {
      throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูล");
    }
    const insigniaType = await this.insigniaTypeRepository.findOne({
      where: { id: requestBody.insigniaTypeId },
    });
    if (!insigniaType) {
      throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูลลำดับชั้นเครื่องราชอิสริยาภรณ์นี้");
    }
    const rowRepeated = await this.insigniaRepository.findOne({
      where: {
        name: requestBody.name,
        isActive: requestBody.isActive,
      },
    });
    if (rowRepeated) {
      throw new HttpError(HttpStatusCode.NOT_FOUND, "ข้อมูล Row นี้มีอยู่ในระบบแล้ว");
    }

    const _insignia = await this.insigniaRepository.findOne({
      select: ["id", "level", "insigniaTypeId"],
      where: { insigniaTypeId: requestBody.insigniaTypeId },
      order: { level: "DESC" },
    });

    insignia.level = _insignia == null ? 1 : _insignia.level + 1;
    insignia.createdUserId = request.user.sub;
    insignia.createdFullName = request.user.name;
    insignia.lastUpdateUserId = request.user.sub;
    insignia.lastUpdateFullName = request.user.name;
    insignia.createdAt = new Date();
    insignia.lastUpdatedAt = new Date();
    await this.insigniaRepository.save(insignia);
    return new HttpSuccess(insignia.id);
  }

  /**
   * API แก้ไขเครื่องราชอิสริยาภรณ์
   *
   * @summary แก้ไขเครื่องราชอิสริยาภรณ์ (ADMIN)
   *
   * @param {string} id  Id เครื่องราชอิสริยาภรณ์
   */
  @Put("{id}")
  async UpdateInsignia(
    @Path() id: string,
    @Body() requestBody: UpdateInsignias,
    @Request() request: { user: Record<string, any> },
  ) {
    const insignia = await this.insigniaRepository.findOne({
      where: { id: id },
    });
    if (!insignia) {
      throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูลเครื่องราชอิสริยาภรณ์นี้");
    }
    const insigniaType = await this.insigniaTypeRepository.findOne({
      where: { id: requestBody.insigniaTypeId },
    });
    if (!insigniaType) {
      throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูลลำดับชั้นเครื่องราชอิสริยาภรณ์นี้");
    }
    const rowRepeated = await this.insigniaRepository.findOne({
      where: {
        id: Not(id),
        name: requestBody.name,
        isActive: requestBody.isActive,
      },
    });
    if (rowRepeated) {
      throw new HttpError(HttpStatusCode.NOT_FOUND, "ข้อมูล Row นี้มีอยู่ในระบบแล้ว");
    }

    insignia.lastUpdateUserId = request.user.sub;
    insignia.lastUpdateFullName = request.user.name;
    insignia.lastUpdatedAt = new Date();
    this.insigniaRepository.merge(insignia, requestBody);
    await this.insigniaRepository.save(insignia);
    return new HttpSuccess(insignia.id);
  }

  /**
   * API ลบเครื่องราชอิสริยาภรณ์
   *
   * @summary ORG_ - ลบเครื่องราชอิสริยาภรณ์ (ADMIN) #
   *
   * @param {string} id  Id เครื่องราชอิสริยาภรณ์
   */
  @Delete("{id}")
  async delete(@Path() id: string) {
    const delInsignia = await this.insigniaRepository.findOne({ where: { id } });
    if (!delInsignia) {
      throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูลเครื่องราชอิสริยาภรณ์นี้");
    }
    await this.insigniaRepository.remove(delInsignia);

    const insignia = await this.insigniaRepository.find({
      select: ["id", "level", "insigniaTypeId"],
      where: { insigniaTypeId: delInsignia.insigniaTypeId },
      order: { level: "DESC" },
    });

    const sortLevel = insignia.map((data, i) => ({
      id: data.id,
      level: i + 1,
    }));
    await this.insigniaRepository.save(sortLevel);

    return new HttpSuccess();
  }

  /**
   * API รายละเอียดเครื่องราชอิสริยาภรณ์
   *
   * @summary ORG_037 - รายละเอียดเครื่องราชอิสริยาภรณ์ (ADMIN) #
   *
   * @param {string} id  Id เครื่องราชอิสริยาภรณ์
   */
  @Get("{id}")
  async GetInsigniaById(@Path() id: string) {
    const insignia = await this.insigniaRepository.findOne({
      relations: ["insigniaType"],
      select: [
        "id",
        "name",
        "shortName",
        "createdAt",
        "lastUpdatedAt",
        "lastUpdateFullName",
        "isActive",
        "note",
      ],
      where: { id: id },
    });
    if (!insignia) {
      throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูลเครื่องราชอิสริยาภรณ์นี้");
    }
    const mapInsignia = {
      id: insignia.id,
      name: insignia.name,
      shortName: insignia.shortName,
      insigniaTypeName: insignia.insigniaType == null ? null : insignia.insigniaType.name, //ลำดับชั้นเครื่องราช
      createdAt: insignia.createdAt,
      lastUpdatedAt: insignia.lastUpdatedAt,
      lastUpdateFullName: insignia.lastUpdateFullName,
      isActive: insignia.isActive,
      note: insignia.note,
    };
    return new HttpSuccess(mapInsignia);
  }

  /**
   * API รายการเครื่องราชอิสริยาภรณ์
   *
   * @summary ORG_ - รายการเครื่องราชอิสริยาภรณ์ (ADMIN) #
   *
   */
  @Get()
  async GetInsignia() {
    const insigniaAll = await this.insigniaRepository.find({
      relations: ["insigniaType"],
      select: [
        "id",
        "name",
        "shortName",
        "createdAt",
        "lastUpdatedAt",
        "lastUpdateFullName",
        "isActive",
        "note",
        "insigniaTypeId",
      ],
      order: { level: "ASC" },
    });

    const mapInsigniaAll = insigniaAll.map((item) => ({
      id: item.id,
      name: item.name,
      shortName: item.shortName,
      insigniaTypeId: item.insigniaTypeId ?? null,
      insigniaTypeName: item.insigniaType == null ? null : item.insigniaType.name, //ลำดับชั้นเครื่องราช
      createdAt: item.createdAt,
      lastUpdatedAt: item.lastUpdatedAt,
      lastUpdateFullName: item.lastUpdateFullName,
      isActive: item.isActive,
      note: item.note,
    }));
    return new HttpSuccess(mapInsigniaAll);
  }

  /**
   * API รายการเครื่องราชอิสริยาภรณ์ (เช็คสิทธิ์)
   *
   * @summary ORG_ - รายการเครื่องราชอิสริยาภรณ์ (ADMIN) #เช็คสิทธิ์
   *
   * @param {string} path  เมนูเช็คสิทธิ์
   */
  @Get("path/{path}")
  async GetInsigniaPath(@Path() path: string, @Request() request: RequestWithUser) {
    path = path.toLocaleUpperCase();
    let getPermission: string = "";
    if (path == "MANAGE") {
      getPermission = "SYS_INSIGNIA_MANAGE";
    } else if (path == "RECORD") {
      getPermission = "SYS_INSIGNIA_RECORD";
    } else if (path == "ALLOCATE") {
      getPermission = "SYS_INSIGNIA_ALLOCATE";
    } else if (path == "BORROW") {
      getPermission = "SYS_INSIGNIA_BORROW";
    } else {
      getPermission = "SYS_INSIGNIA_MANAGE";
    }
    await new permission().PermissionList(request, getPermission);
    const insigniaAll = await this.insigniaRepository.find({
      relations: ["insigniaType"],
      select: [
        "id",
        "name",
        "shortName",
        "createdAt",
        "lastUpdatedAt",
        "lastUpdateFullName",
        "isActive",
        "note",
        "insigniaTypeId",
      ],
      where: { isActive: true },
      order: { level: "ASC" },
    });

    const mapInsigniaAll = insigniaAll.map((item) => ({
      id: item.id,
      name: item.name,
      shortName: item.shortName,
      insigniaTypeId: item.insigniaTypeId ?? null,
      insigniaTypeName: item.insigniaType == null ? null : item.insigniaType.name, //ลำดับชั้นเครื่องราช
      createdAt: item.createdAt,
      lastUpdatedAt: item.lastUpdatedAt,
      lastUpdateFullName: item.lastUpdateFullName,
      isActive: item.isActive,
      note: item.note,
    }));
    return new HttpSuccess(mapInsigniaAll);
  }

  /**
   * API จัดลำดับแสดงผลเครื่องราชอิสริยาภรณ์
   *
   * @summary ORG_038 - จัดลำดับแสดงผลเครื่องราชอิสริยาภรณ์ (ADMIN) #
   *
   */
  @Put("sort/{insigniaTypeId}")
  async Sort(@Path() insigniaTypeId: string, @Body() requestBody: { id: string[] }) {
    const insigniaType = await this.insigniaTypeRepository.findOne({
      where: { id: insigniaTypeId },
    });
    if (!insigniaType) {
      throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบข้อมูลลำดับเครื่องราชอิสริยาภรณ์นี้");
    }

    const insignia = await this.insigniaRepository.find({
      // select: ["id", "level", "insigniaTypeId"],
      where: { insigniaTypeId: insigniaTypeId },
    });

    const sortLevel = insignia.map((data) => ({
      ...data,
      id: data.id,
      level: requestBody.id.indexOf(data.id) + 1,
    }));

    await this.insigniaRepository.save(sortLevel);
    return new HttpSuccess();
  }
}
