import { Position } from "./../entities/Position";
import { ApiKey } from "./../entities/ApiKey";
import { ApiAttribute } from "./../entities/ApiAttribute";
import { CreateApi } from "./../entities/ApiName";
import { PosMaster } from "../entities/PosMaster";
import { OrgChild4 } from "../entities/OrgChild4";
import { OrgChild3 } from "../entities/OrgChild3";
import { OrgChild2 } from "../entities/OrgChild2";
import { OrgChild1 } from "../entities/OrgChild1";
import { OrgRoot } from "../entities/OrgRoot";
import { ProfileEmployee } from "../entities/ProfileEmployee";
import { ProfileSalary } from "../entities/ProfileSalary";
import { ProfileOther } from "../entities/ProfileOther";
import { ProfileNopaid } from "../entities/ProfileNopaid";
import { ProfileLeave } from "../entities/ProfileLeave";
import { ProfileInsignia } from "../entities/ProfileInsignia";
import { ProfileHonor } from "../entities/ProfileHonor";
import { ProfileGovernment } from "../entities/ProfileGovernment";
import { ProfileFamilyMother } from "../entities/ProfileFamilyMother";
import { ProfileFamilyFather } from "../entities/ProfileFamilyFather";
import { ProfileFamilyCouple } from "../entities/ProfileFamilyCouple";
import { ProfileEducation } from "../entities/ProfileEducation";
import { ProfileDuty } from "../entities/ProfileDuty";
import { ProfileDiscipline } from "../entities/ProfileDiscipline";
import { ProfileDevelopment } from "../entities/ProfileDevelopment";
import { ProfileChildren } from "../entities/ProfileChildren";
import { ProfileChangeName } from "../entities/ProfileChangeName";
import { ProfileCertificate } from "../entities/ProfileCertificate";
import { ProfileAssessment } from "../entities/ProfileAssessment";
import { ProfileAbility } from "../entities/ProfileAbility";
import {
  Controller,
  Post,
  Delete,
  Route,
  Security,
  Tags,
  Body,
  Path,
  Request,
  Response,
  Get,
  Put,
  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 { RequestWithUser } from "../middlewares/user";
import { ApiName } from "../entities/ApiName";
import { Profile } from "../entities/Profile";
import { SystemDefinition, EntityDefinition, SystemCode } from "./../interfaces/api-type";
@Route("api/v1/org/api-manage")
@Tags("ApiManage")
@Security("bearerAuth")
@Response(
  HttpStatusCode.INTERNAL_SERVER_ERROR,
  "เกิดข้อผิดพลาด ไม่สามารถแสดงรายการได้ กรุณาลองใหม่ในภายหลัง",
)
export class ApiManageController extends Controller {
  private readonly profileRepository = AppDataSource.getRepository(Profile);
  private readonly profileEmployeeRepository = AppDataSource.getRepository(ProfileEmployee);
  private readonly profileGovernmentRepository = AppDataSource.getRepository(ProfileGovernment);
  private readonly profileProfileSalaryRepository = AppDataSource.getRepository(ProfileSalary);
  private readonly profileAbilityRepository = AppDataSource.getRepository(ProfileAbility);
  private readonly profileAssessmentRepository = AppDataSource.getRepository(ProfileAssessment);
  private readonly profileCertificateRepository = AppDataSource.getRepository(ProfileCertificate);
  private readonly profileHonorRepository = AppDataSource.getRepository(ProfileHonor);
  private readonly profileInsigniaRepository = AppDataSource.getRepository(ProfileInsignia);
  private readonly profileLeaveRepository = AppDataSource.getRepository(ProfileLeave);
  private readonly profileChangeNameRepository = AppDataSource.getRepository(ProfileChangeName);
  private readonly profileDevelopmentRepository = AppDataSource.getRepository(ProfileDevelopment);
  private readonly profileDisciplineRepository = AppDataSource.getRepository(ProfileDiscipline);
  private readonly profileDutyRepository = AppDataSource.getRepository(ProfileDuty);
  private readonly profileEducationRepository = AppDataSource.getRepository(ProfileEducation);
  private readonly profileFamilyCoupleRepository = AppDataSource.getRepository(ProfileFamilyCouple);
  private readonly profileFamilyFatherRepository = AppDataSource.getRepository(ProfileFamilyFather);
  private readonly profileFamilyMotherRepository = AppDataSource.getRepository(ProfileFamilyMother);
  private readonly profileChildrenRepository = AppDataSource.getRepository(ProfileChildren);
  private readonly profileNopaidRepository = AppDataSource.getRepository(ProfileNopaid);
  private readonly profileOtherRepository = AppDataSource.getRepository(ProfileOther);
  private readonly orgRootRepository = AppDataSource.getRepository(OrgRoot);
  private readonly orgChild1Repository = AppDataSource.getRepository(OrgChild1);
  private readonly orgChild2Repository = AppDataSource.getRepository(OrgChild2);
  private readonly orgChild3Repository = AppDataSource.getRepository(OrgChild3);
  private readonly orgChild4Repository = AppDataSource.getRepository(OrgChild4);
  private readonly posMasterRepository = AppDataSource.getRepository(PosMaster);
  private readonly positionRepository = AppDataSource.getRepository(Position);

  // รายการระบบ
  private readonly systems: SystemDefinition[] = [
    {
      code: "registry",
      name: "ข้อมูลทะเบียนประวัติข้าราชการ",
    },
    {
      code: "registry_emp",
      name: "ข้อมูลทะเบียนประวัติลูกจ้างประจำ",
    },
    {
      code: "registry_temp",
      name: "ข้อมูลทะเบียนประวัติลูกจ้างชั่วคราว",
    },
    {
      code: "organization",
      name: "ข้อมูลโครงสร้าง",
    },
    // {
    //   code: "position",
    //   name: "ข้อมูลอัตรากำลัง",
    // },
  ];

  // รายการเอนทิตีทั้งหมด
  private readonly entities: EntityDefinition[] = [
    {
      name: "Profile",
      repository: this.profileRepository,
      description: "ข้อมูลหลัก",
      isMain: true,
      system: ["registry"],
    },
    {
      name: "ProfileEmployee",
      repository: this.profileEmployeeRepository,
      description: "ข้อมูลหลัก",
      isMain: true,
      system: ["registry_emp", "registry_temp"],
    },
    {
      name: "ProfileGovernment",
      repository: this.profileGovernmentRepository,
      description: "ข้อมูลราชการ",
      system: ["registry", "registry_emp", "registry_temp"],
    },
    {
      name: "ProfileSalary",
      repository: this.profileProfileSalaryRepository,
      description: "ข้อมูลตำแหน่ง/เงินเดือน",
      system: ["registry", "registry_emp", "registry_temp"],
    },
    {
      name: "ProfileAbility",
      repository: this.profileAbilityRepository,
      description: "ข้อมูลความสามารถ",
      system: ["registry", "registry_emp", "registry_temp"],
    },
    {
      name: "ProfileAssessment",
      repository: this.profileAssessmentRepository,
      description: "ข้อมูลการประเมิน",
      system: ["registry", "registry_emp", "registry_temp"],
    },
    {
      name: "ProfileCertificate",
      repository: this.profileCertificateRepository,
      description: "ข้อมูลใบรับรอง",
      system: ["registry", "registry_emp", "registry_temp"],
    },
    {
      name: "ProfileHonor",
      repository: this.profileHonorRepository,
      description: "ข้อมูลเกียรติบัตร",
      system: ["registry", "registry_emp", "registry_temp"],
    },
    {
      name: "ProfileInsignia",
      repository: this.profileInsigniaRepository,
      description: "ข้อมูลเครื่องหมาย",
      system: ["registry", "registry_emp", "registry_temp"],
    },
    {
      name: "ProfileLeave",
      repository: this.profileLeaveRepository,
      description: "ข้อมูลการลา",
      system: ["registry", "registry_emp", "registry_temp"],
    },
    {
      name: "ProfileChangeName",
      repository: this.profileChangeNameRepository,
      description: "ข้อมูลการเปลี่ยนชื่อ",
      system: ["registry", "registry_emp", "registry_temp"],
    },
    {
      name: "ProfileDevelopment",
      repository: this.profileDevelopmentRepository,
      description: "ข้อมูลการพัฒนา",
      system: ["registry", "registry_emp", "registry_temp"],
    },
    {
      name: "ProfileDiscipline",
      repository: this.profileDisciplineRepository,
      description: "ข้อมูลวินัย",
      system: ["registry", "registry_emp", "registry_temp"],
    },
    {
      name: "ProfileDuty",
      repository: this.profileDutyRepository,
      description: "ข้อมูลหน้าที่ปฏิบัติราชการ",
      system: ["registry", "registry_emp", "registry_temp"],
    },
    {
      name: "ProfileEducation",
      repository: this.profileEducationRepository,
      description: "ข้อมูลการศึกษา",
      system: ["registry", "registry_emp", "registry_temp"],
    },
    {
      name: "ProfileFamilyCouple",
      repository: this.profileFamilyCoupleRepository,
      description: "ข้อมูลคู่สมรส",
      system: ["registry", "registry_emp", "registry_temp"],
    },
    {
      name: "ProfileFamilyFather",
      repository: this.profileFamilyFatherRepository,
      description: "ข้อมูลบิดา",
      system: ["registry", "registry_emp", "registry_temp"],
    },
    {
      name: "ProfileFamilyMother",
      repository: this.profileFamilyMotherRepository,
      description: "ข้อมูลมารดา",
      system: ["registry", "registry_emp", "registry_temp"],
    },
    {
      name: "ProfileChildren",
      repository: this.profileChildrenRepository,
      description: "ข้อมูลบุตร",
      system: ["registry", "registry_emp", "registry_temp"],
    },
    {
      name: "ProfileNopaid",
      repository: this.profileNopaidRepository,
      description: "ข้อมูลการไม่จ่ายเงินเดือน",
      system: ["registry", "registry_emp", "registry_temp"],
    },
    {
      name: "ProfileOther",
      repository: this.profileOtherRepository,
      description: "ข้อมูลอื่นๆ",
      system: ["registry", "registry_emp", "registry_temp"],
    },
    {
      name: "OrgRoot",
      repository: this.orgRootRepository,
      description: "ข้อมูลหน่วยงาน",
      isMain: true,
      system: ["organization"],
    },
    {
      name: "OrgChild1",
      repository: this.orgChild1Repository,
      description: "ข้อมูลส่วนราชการ ระดับที่ 1",
      system: ["organization"],
    },
    {
      name: "OrgChild2",
      repository: this.orgChild2Repository,
      description: "ข้อมูลส่วนราชการ ระดับที่ 2",
      system: ["organization"],
    },
    {
      name: "OrgChild3",
      repository: this.orgChild3Repository,
      description: "ข้อมูลส่วนราชการ ระดับที่ 3",
      system: ["organization"],
    },
    {
      name: "OrgChild4",
      repository: this.orgChild4Repository,
      description: "ข้อมูลส่วนราชการ ระดับที่ 4",
      system: ["organization"],
    },
    // {
    //   name: "PosMaster",
    //   repository: this.posMasterRepository,
    //   description: "ข้อมูลอัตรากำลัง",
    //   isMain: true,
    //   system: ["position"],
    // },
    // {
    //   name: "Position",
    //   repository: this.positionRepository,
    //   description: "ข้อมูลตำแหน่ง",
    //   system: ["position"],
    // },
    // {
    //   name: "OrgRoot",
    //   repository: this.orgRootRepository,
    //   description: "ข้อมูลหน่วยงาน",
    //   system: ["position"],
    // },
    // {
    //   name: "OrgChild1",
    //   repository: this.orgChild1Repository,
    //   description: "ข้อมูลส่วนราชการ ระดับที่ 1",
    //   system: ["position"],
    // },
    // {
    //   name: "OrgChild2",
    //   repository: this.orgChild2Repository,
    //   description: "ข้อมูลส่วนราชการ ระดับที่ 2",
    //   system: ["position"],
    // },
    // {
    //   name: "OrgChild3",
    //   repository: this.orgChild3Repository,
    //   description: "ข้อมูลส่วนราชการ ระดับที่ 3",
    //   system: ["position"],
    // },
    // {
    //   name: "OrgChild4",
    //   repository: this.orgChild4Repository,
    //   description: "ข้อมูลส่วนราชการ ระดับที่ 4",
    //   system: ["position"],
    // },
    // {
    //   name: "Profile",
    //   repository: this.profileRepository,
    //   description: "ข้อมูลคนครอง",
    //   system: ["position"],
    // },
  ];

  private readonly DEFAULT_PAGE_SIZE = 10; // ขนาดหน้าเริ่มต้น
  private readonly EXCLUDED_COLUMNS = [
    "createdUserId",
    "lastUpdateUserId",
    "createdAt",
    "createdFullName",
    "lastUpdateFullName",
    "avatarName",
    "profileId",
    "prefixId",
    "profileEmployeeId",
    "documentId",
    "orgRevisionId",
    "posMasterId",
    "orgRootId",
    "orgChild1Id",
    "orgChild2Id",
    "orgChild3Id",
    "orgChild4Id",
    "keycloak",
    "commandId",
    "prefixMain",
    "authRoleId",
    "next_holderId",
    "current_holderId",
    "ancestorDNA",
    "leaveCommandId",
    "posLevelId",
    "posTypeId",
    "posExecutiveId",
    "registrationProvinceId",
    "registrationDistrictId",
    "registrationSubDistrictId",
    "currentProvinceId",
    "currentDistrictId",
    "currentSubDistrictId",
    "isDelete",
    "keycloak",
    "statusCheckEdit",
    "privacyCheckin",
    "privacyUser",
    "privacyMgt",
    "dutyTimeId",
    "dutyTimeEffectiveDate",
    "profileId",
    "profileEmployeeId",
    "orgRevisionId",
    "rank",
    "isUpload",
    "isDeleted",
    "isEntry",
    "prefixId",
    "leaveId",
    "leaveTypeId",
    "isDeputy",
    "isCommission",
  ]; // ฟิลด์ที่ไม่ต้องการแสดงในผลลัพธ์

  // การแทนที่ฟิลด์ ID ด้วยฟิลด์ Name สำหรับ Profile entity
  private readonly PROFILE_FIELD_REPLACEMENTS: Record<
    string,
    { propertyName: string; type: string; comment: string; joinTable: string; joinField: string }
  > = {
    posLevelId: {
      propertyName: "posLevelName",
      type: "string",
      comment: "ระดับตำแหน่ง",
      joinTable: "PosLevel",
      joinField: "posLevelName",
    },
    posTypeId: {
      propertyName: "posTypeName",
      type: "string",
      comment: "ประเภทตำแหน่ง",
      joinTable: "PosType",
      joinField: "posTypeName",
    },
    registrationProvinceId: {
      propertyName: "registrationProvinceName",
      type: "string",
      comment: "จังหวัดตามทะเบียนบ้าน",
      joinTable: "Province",
      joinField: "name",
    },
    registrationDistrictId: {
      propertyName: "registrationDistrictName",
      type: "string",
      comment: "เขตตามทะเบียนบ้าน",
      joinTable: "District",
      joinField: "name",
    },
    registrationSubDistrictId: {
      propertyName: "registrationSubDistrictName",
      type: "string",
      comment: "แขวงตามทะเบียนบ้าน",
      joinTable: "SubDistrict",
      joinField: "name",
    },
    currentProvinceId: {
      propertyName: "currentProvinceName",
      type: "string",
      comment: "จังหวัดตามปัจจุบัน",
      joinTable: "Province",
      joinField: "name",
    },
    currentDistrictId: {
      propertyName: "currentDistrictName",
      type: "string",
      comment: "เขตตามปัจจุบัน",
      joinTable: "District",
      joinField: "name",
    },
    currentSubDistrictId: {
      propertyName: "currentSubDistrictName",
      type: "string",
      comment: "แขวงตามปัจจุบัน",
      joinTable: "SubDistrict",
      joinField: "name",
    },
  };

  // การแทนที่ฟิลด์ ID ด้วยฟิลด์ Name สำหรับ Position entity
  private readonly POSITION_FIELD_REPLACEMENTS: Record<
    string,
    { propertyName: string; type: string; comment: string; joinTable: string; joinField: string }
  > = {
    posTypeId: {
      propertyName: "posTypeName",
      type: "string",
      comment: "ประเภทตำแหน่ง",
      joinTable: "PosType",
      joinField: "posTypeName",
    },
    posLevelId: {
      propertyName: "posLevelName",
      type: "string",
      comment: "ระดับตำแหน่ง",
      joinTable: "PosLevel",
      joinField: "posLevelName",
    },
    posExecutiveId: {
      propertyName: "posExecutiveName",
      type: "string",
      comment: "ตำแหน่งทางการบริหาร",
      joinTable: "PosExecutive",
      joinField: "posExecutiveName",
    },
  };

  // การแทนที่ฟิลด์ ID ด้วยฟิลด์ Name สำหรับ ProfileEmployee entity
  private readonly PROFILEEMPLOYEE_FIELD_REPLACEMENTS: Record<
    string,
    { propertyName: string; type: string; comment: string; joinTable: string; joinField: string }
  > = {
    posLevelId: {
      propertyName: "posLevelName",
      type: "string",
      comment: "ระดับชั้นงาน",
      joinTable: "EmployeePosLevel",
      joinField: "posLevelName",
    },
    posTypeId: {
      propertyName: "posTypeName",
      type: "string",
      comment: "กลุ่มงาน",
      joinTable: "EmployeePosType",
      joinField: "posTypeName",
    },
  };

  // การแทนที่ฟิลด์ ID ด้วยฟิลด์ Name สำหรับ ProfileLeave entity
  private readonly PROFILELEAVE_FIELD_REPLACEMENTS: Record<
    string,
    { propertyName: string; type: string; comment: string; joinTable: string; joinField: string }
  > = {
    leaveTypeId: {
      propertyName: "leaveTypeName",
      type: "string",
      comment: "ประเภทการลา",
      joinTable: "LeaveType",
      joinField: "name",
    },
  };

  private validateSuperAdminRole(user: any): void {
    if (!user.role.includes("SUPER_ADMIN")) {
      throw new HttpError(HttpStatusCode.FORBIDDEN, "คุณไม่มีสิทธิ์ในการเข้าถึงข้อมูลนี้");
    }
  }

  private generateApiCode(): string {
    return Math.random().toString(36).substring(2, 10).toUpperCase();
  }

  private createApiPath(system: SystemCode = "registry", code: string): string {
    return `/api/v1/org/api-service/${system}/${code}`;
  }

  /**
   * list systems
   * @summary รายการ systems
   */
  @Get("/systems")
  async listSystems(): Promise<HttpSuccess> {
    return new HttpSuccess(this.systems);
  }

  /**
   * list fields by systems
   * @summary รายการ fields ตาม systems
   */
  @Get("/:system/fields")
  async listAttribute(
    @Request() req: RequestWithUser,
    @Path("system") system: SystemCode,
  ): Promise<HttpSuccess | HttpError> {
    try {
      this.validateSuperAdminRole(req.user);

      const result = this.entities
        .filter((entity) => entity.system.includes(system))
        .map(({ name, repository, description, isMain }) => {
          let columns = repository.metadata.columns
            .filter(
              (column: any) =>
                !column.isPrimary && !this.EXCLUDED_COLUMNS.includes(column.propertyName),
            )
            .map((column: any) => ({
              propertyName: column.propertyName,
              type: typeof column.type === "string" ? column.type : "string",
              comment: column.comment,
              key: column.propertyName,
            }));

          // Special handling for Profile entity - replace ID fields with name fields
          if (name === "Profile") {
            const replacementKeys = Object.keys(this.PROFILE_FIELD_REPLACEMENTS);

            // Remove ID fields that should be replaced
            columns = columns.filter(
              (col: { propertyName: string }) => !replacementKeys.includes(col.propertyName),
            );

            // Add the corresponding name fields
            const nameFields = replacementKeys.map((key) => ({
              propertyName: this.PROFILE_FIELD_REPLACEMENTS[key].propertyName,
              type: "string",
              comment: this.PROFILE_FIELD_REPLACEMENTS[key].comment,
              key: this.PROFILE_FIELD_REPLACEMENTS[key].propertyName,
            }));

            columns = [...columns, ...nameFields];
          }

          // Special handling for Position entity - replace ID fields with name fields
          if (name === "Position") {
            const replacementKeys = Object.keys(this.POSITION_FIELD_REPLACEMENTS);

            // Remove ID fields that should be replaced
            columns = columns.filter(
              (col: { propertyName: string }) => !replacementKeys.includes(col.propertyName),
            );

            // Add the corresponding name fields
            const nameFields = replacementKeys.map((key) => ({
              propertyName: this.POSITION_FIELD_REPLACEMENTS[key].propertyName,
              type: "string",
              comment: this.POSITION_FIELD_REPLACEMENTS[key].comment,
              key: this.POSITION_FIELD_REPLACEMENTS[key].propertyName,
            }));

            columns = [...columns, ...nameFields];
          }

          // Special handling for ProfileEmployee entity - replace ID fields with name fields
          if (name === "ProfileEmployee") {
            const replacementKeys = Object.keys(this.PROFILEEMPLOYEE_FIELD_REPLACEMENTS);

            // Remove ID fields that should be replaced
            columns = columns.filter(
              (col: { propertyName: string }) => !replacementKeys.includes(col.propertyName),
            );

            // Add the corresponding name fields
            const nameFields = replacementKeys.map((key) => ({
              propertyName: this.PROFILEEMPLOYEE_FIELD_REPLACEMENTS[key].propertyName,
              type: "string",
              comment: this.PROFILEEMPLOYEE_FIELD_REPLACEMENTS[key].comment,
              key: this.PROFILEEMPLOYEE_FIELD_REPLACEMENTS[key].propertyName,
            }));

            columns = [...columns, ...nameFields];
          }

          // Special handling for ProfileLeave entity - replace ID fields with name fields
          if (name === "ProfileLeave") {
            const replacementKeys = Object.keys(this.PROFILELEAVE_FIELD_REPLACEMENTS);

            // Remove ID fields that should be replaced
            columns = columns.filter(
              (col: { propertyName: string }) => !replacementKeys.includes(col.propertyName),
            );

            // Add the corresponding name fields
            const nameFields = replacementKeys.map((key) => ({
              propertyName: this.PROFILELEAVE_FIELD_REPLACEMENTS[key].propertyName,
              type: "string",
              comment: this.PROFILELEAVE_FIELD_REPLACEMENTS[key].comment,
              key: this.PROFILELEAVE_FIELD_REPLACEMENTS[key].propertyName,
            }));

            columns = [...columns, ...nameFields];
          }

          // Special handling for PosMaster entity - add Profile fields for holder information
          if (name === "PosMaster") {
            // Add Profile fields that are accessible via current_holder relation
            const profileFields = ["prefix", "rank", "firstName", "lastName", "citizenId"];
            const profileRepository = AppDataSource.getRepository(Profile);
            const profileColumns = profileRepository.metadata.columns
              .filter(
                (column: any) => !column.isPrimary && profileFields.includes(column.propertyName),
              )
              .map((column: any) => ({
                propertyName: `Profile.${column.propertyName}`,
                type: typeof column.type === "string" ? column.type : "string",
                comment: column.comment,
                key: `Profile.${column.propertyName}`,
              }));

            columns = [...columns, ...profileColumns];
          }

          return {
            tb: name,
            description,
            isMain: isMain || false,
            propertys: columns,
          };
        });

      return new HttpSuccess(result);
    } catch (error) {
      throw new HttpError(
        HttpStatusCode.INTERNAL_SERVER_ERROR,
        (error instanceof Error ? error.message : String(error)) ||
          "เกิดข้อผิดพลาด ไม่สามารถแสดงรายการได้ กรุณาลองใหม่ในภายหลัง",
      );
    }
  }

  /**
   * list api
   * @summary รายการ api
   */
  @Get("/lists")
  async listApi(
    @Request() req: RequestWithUser,
    @Query("page") page: number = 1,
    @Query("pageSize") pageSize: number = this.DEFAULT_PAGE_SIZE,
    @Query("keyword") keyword: string = "",
    @Query("system") system: SystemCode | "" = "",
    @Query("isActive") isActive: boolean = true,
  ): Promise<HttpSuccess | HttpError> {
    try {
      this.validateSuperAdminRole(req.user);

      const offset = (page - 1) * pageSize;
      const queryBuilder = AppDataSource.getRepository(ApiName)
        .createQueryBuilder("apiName")
        .where("apiName.isActive = :isActive", { isActive })
        .select([
          "apiName.id",
          "apiName.name",
          "apiName.code",
          "apiName.pathApi",
          "apiName.methodApi",
          "apiName.system",
          "apiName.isActive",
          "apiName.createdAt",
          "apiName.lastUpdatedAt",
        ]);

      if (keyword?.trim()) {
        queryBuilder.andWhere(
          "(apiName.name LIKE :keyword OR apiName.code LIKE :keyword OR apiName.pathApi LIKE :keyword)",
          { keyword: `%${keyword.trim()}%` },
        );
      }

      if (system) {
        queryBuilder.andWhere("apiName.system = :system", { system });
      }

      const [apiNames, total] = await queryBuilder
        .skip(offset)
        .take(pageSize)
        .orderBy("apiName.lastUpdatedAt", "DESC")
        .addOrderBy("apiName.createdAt", "ASC")
        .getManyAndCount();

      return new HttpSuccess({
        data: apiNames.map((api) => ({
          ...api,
          system: this.systems.find((s) => s.code === api.system)?.name || api.system,
        })),
        total,
      });
    } catch (error) {
      throw new HttpError(
        HttpStatusCode.INTERNAL_SERVER_ERROR,
        (error instanceof Error ? error.message : String(error)) ||
          "เกิดข้อผิดพลาด ไม่สามารถแสดงรายการได้ กรุณาลองใหม่ในภายหลัง",
      );
    }
  }

  /**
   * สร้าง api
   * @summary สร้าง api
   */
  @Post("")
  async createApi(
    @Request() req: RequestWithUser,
    @Body() apiData: CreateApi,
  ): Promise<HttpSuccess | HttpError> {
    const queryRunner = AppDataSource.createQueryRunner();
    await queryRunner.connect();
    await queryRunner.startTransaction();

    try {
      this.validateSuperAdminRole(req.user);

      const code = this.generateApiCode();
      const postData = {
        name: apiData.name,
        code,
        pathApi: this.createApiPath(apiData.system as SystemCode, code),
        methodApi: apiData.methodApi || "GET",
        system: apiData.system || "registry",
        isActive: apiData.isActive || false,
        createdUserId: req.user?.sub,
        createdFullName: req.user?.name || "",
      };

      const apiName = await queryRunner.manager.getRepository(ApiName).save(postData);

      if (apiData.apiAttributes?.length) {
        let orderingCounter = 0;
        const attributesToSave = apiData.apiAttributes.flatMap((attr) =>
          attr.propertyKey.map((propertyKey) => ({
            apiNameId: apiName.id,
            tbName: attr.tbName,
            propertyKey,
            ordering: orderingCounter++,
            createdUserId: req.user?.sub,
            createdFullName: req.user?.name || "",
          })),
        );

        await queryRunner.manager.getRepository(ApiAttribute).save(attributesToSave);
      }

      await queryRunner.commitTransaction();
      return new HttpSuccess(apiName.id);
    } catch (error) {
      await queryRunner.rollbackTransaction();
      throw new HttpError(
        HttpStatusCode.INTERNAL_SERVER_ERROR,
        (error instanceof Error ? error.message : String(error)) ||
          "เกิดข้อผิดพลาด ไม่สามารถบันทึกข้อมูลได้ กรุณาลองใหม่ในภายหลัง",
      );
    } finally {
      await queryRunner.release();
    }
  }

  /**
   * รายละเอียด api ตามไอดี
   * @summary รายละเอียด api ตามไอดี
   */
  @Get("/{id}")
  async getApiById(
    @Request() req: RequestWithUser,
    @Path("id") id: string,
  ): Promise<HttpSuccess | HttpError> {
    try {
      this.validateSuperAdminRole(req.user);

      const apiName = await AppDataSource.getRepository(ApiName).findOne({
        select: {
          id: true,
          name: true,
          code: true,
          pathApi: true,
          methodApi: true,
          system: true,
          isActive: true,
          apiAttributes: true,
        },
        where: { id },
        relations: ["apiAttributes"],
        order: {
          apiAttributes: {
            ordering: "ASC",
          },
        },
      });

      if (!apiName) {
        throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบ API ที่ต้องการแก้ไข");
      }

      const items = {
        ...apiName,
        apiAttributes: apiName.apiAttributes.map((attr) => ({
          tbName: attr.tbName,
          propertyKey: attr.propertyKey,
        })),
      };

      return new HttpSuccess(items);
    } catch (error) {
      throw new HttpError(
        HttpStatusCode.INTERNAL_SERVER_ERROR,
        (error instanceof Error ? error.message : String(error)) ||
          "เกิดข้อผิดพลาด ไม่สามารถบันทึกข้อมูลได้ กรุณาลองใหม่ในภายหลัง",
      );
    }
  }

  /**
   * แก้ไข api
   * @summary แก้ไขข้อมูล api
   */
  @Put("/{id}")
  async editApi(
    @Request() req: RequestWithUser,
    @Path("id") id: string,
    @Body() apiData: CreateApi,
  ): Promise<HttpSuccess | HttpError> {
    const queryRunner = AppDataSource.createQueryRunner();
    await queryRunner.connect();
    await queryRunner.startTransaction();

    try {
      this.validateSuperAdminRole(req.user);

      const apiName = await queryRunner.manager.getRepository(ApiName).findOneBy({ id });
      if (!apiName) {
        throw new HttpError(HttpStatusCode.NOT_FOUND, "ไม่พบ API ที่ต้องการแก้ไข");
      }

      const updateData = {
        name: apiData.name,
        pathApi: this.createApiPath(apiData.system as SystemCode, apiName.code),
        methodApi: apiData.methodApi || "GET",
        system: apiData.system || "registry",
        isActive: apiData.isActive || false,
        lastUpdateUserId: req.user?.sub,
        lastUpdateFullName: req.user?.name || "",
      };

      await queryRunner.manager.getRepository(ApiName).update(id, updateData);
      await queryRunner.manager.getRepository(ApiAttribute).delete({ apiNameId: id });

      if (apiData.apiAttributes?.length) {
        let orderingCounter = 0;
        const attributesToSave = apiData.apiAttributes.flatMap((attr) =>
          attr.propertyKey.map((propertyKey) => ({
            apiNameId: apiName.id,
            tbName: attr.tbName,
            propertyKey,
            ordering: orderingCounter++,
            lastUpdateUserId: req.user?.sub,
            lastUpdateFullName: req.user?.name || "",
          })),
        );

        await queryRunner.manager.getRepository(ApiAttribute).save(attributesToSave);
      }

      await queryRunner.commitTransaction();
      return new HttpSuccess();
    } catch (error) {
      await queryRunner.rollbackTransaction();
      throw new HttpError(
        HttpStatusCode.INTERNAL_SERVER_ERROR,
        (error instanceof Error ? error.message : String(error)) ||
          "เกิดข้อผิดพลาด ไม่สามารถบันทึกข้อมูลได้ กรุณาลองใหม่ในภายหลัง",
      );
    } finally {
      await queryRunner.release();
    }
  }

  /**
   * ลบ api
   * @summary ลบข้อมูล api
   */
  @Delete("/{id}")
  async deleteApi(
    @Request() req: RequestWithUser,
    @Path("id") id: string,
  ): Promise<HttpSuccess | HttpError> {
    const queryRunner = AppDataSource.createQueryRunner();
    await queryRunner.connect();
    await queryRunner.startTransaction();

    try {
      this.validateSuperAdminRole(req.user);

      const checkUsed = await AppDataSource.getRepository(ApiKey)
        .createQueryBuilder("apiKey")
        .innerJoin("apiKey.apiNames", "apiName")
        .where("apiName.id = :id", { id })
        .getCount();

      if (checkUsed > 0) {
        throw new HttpError(
          HttpStatusCode.BAD_REQUEST,
          "ไม่สามารถลบ API นี้ได้ เนื่องจากมีการใช้งานอยู่",
        );
      }

      await queryRunner.manager.getRepository(ApiAttribute).delete({ apiNameId: id });
      await queryRunner.manager.getRepository(ApiName).delete({ id });

      await queryRunner.commitTransaction();
      return new HttpSuccess();
    } catch (error) {
      await queryRunner.rollbackTransaction();
      throw new HttpError(
        HttpStatusCode.INTERNAL_SERVER_ERROR,
        (error instanceof Error ? error.message : String(error)) ||
          "เกิดข้อผิดพลาด ไม่สามารถบันทึกข้อมูลได้ กรุณาลองใหม่ในภายหลัง",
      );
    } finally {
      await queryRunner.release();
    }
  }

  /**
   * list systems
   * @summary รายการ systems
   */
  @Get("/manual/swagger")
  async getManualRequestWebService(): Promise<HttpSuccess> {
    const json = {
      openapi: "3.0.0",
      info: {
        title: "Request Web Service",
        version: "1.0.0",
        description: "This is a manual request web service.",
      },
      servers: [
        {
          url: process.env.API_URL?.replace("/api/v1", "") || "http://localhost:13009",
        },
        {
          url: "http://localhost:13009",
          description: "Local server",
        },
      ],
      paths: {
        "/api/v1/org/api-service/{system}/{code}": {
          get: {
            summary: "Get Registry Data",
            parameters: [
              {
                name: "system",
                in: "path",
                required: true,
                schema: {
                  type: "string",
                  enum: ["registry", "registry_emp", "registry_temp", "organization", "position"],
                },
              },
              {
                name: "code",
                in: "path",
                required: true,
                schema: {
                  type: "string",
                },
              },
              {
                name: "page",
                in: "query",
                required: false,
                schema: {
                  type: "integer",
                  default: 1,
                },
              },
              {
                name: "pageSize",
                in: "query",
                required: false,
                schema: {
                  type: "integer",
                  default: 100,
                },
              },
            ],
            responses: {
              200: {
                description: "Successful response",
              },
              400: {
                description: "Bad request",
              },
              500: {
                description: "Internal server error",
              },
            },
          },
        },
      },
      components: {
        securitySchemes: {
          ApiKeyAuth: {
            type: "apiKey",
            in: "header",
            name: "X-API-Key",
          },
        },
      },
      security: [
        {
          ApiKeyAuth: [],
        },
      ],
    };

    return new HttpSuccess(json);
  }
}
