import { BaseRepository } from "@edr/api-common";
import { Injectable } from "@nestjs/common";
import { InjectRepository } from "@nestjs/typeorm";
import { Repository } from "typeorm";

import { DropdownOption } from "./entities/dropdown-option.entity";
import { DropdownSetting } from "./entities/dropdown-setting.entity";
import type { IDropdownSettingsRepository } from "./interfaces/dropdown-settings.repository.interface";

@Injectable()
export class DropdownSettingsRepository
  extends BaseRepository<DropdownSetting>
  implements IDropdownSettingsRepository
{
  constructor(
    @InjectRepository(DropdownSetting)
    repository: Repository<DropdownSetting>,
    @InjectRepository(DropdownOption)
    private readonly optionsRepository: Repository<DropdownOption>,
  ) {
    super(repository);
  }

  findByCode(code: string): Promise<DropdownSetting | null> {
    return this.repository.findOne({
      where: { code },
      relations: { children: true },
      order: { children: { order: "ASC" } },
    });
  }

  override findById(id: string): Promise<DropdownSetting | null> {
    return this.repository.findOne({
      where: { id },
      relations: { children: true },
      order: { children: { order: "ASC" } },
    });
  }

  override findAll(): Promise<DropdownSetting[]> {
    return this.repository.find({
      order: { label: "ASC", children: { order: "ASC" } },
      relations: { children: true },
    });
  }

  async replaceOptions(
    settingId: string,
    options: Array<Partial<DropdownOption>>,
  ): Promise<DropdownOption[]> {
    await this.optionsRepository.delete({ settingId });
    if (options.length === 0) return [];
    const entities = options.map((o, idx) =>
      this.optionsRepository.create({
        ...o,
        settingId,
        order: o.order ?? idx + 1,
      }),
    );
    return this.optionsRepository.save(entities);
  }

  async addOption(
    settingId: string,
    option: Partial<DropdownOption>,
  ): Promise<DropdownOption> {
    const entity = this.optionsRepository.create({ ...option, settingId });
    return this.optionsRepository.save(entity);
  }

  async updateOption(
    optionId: string,
    data: Partial<DropdownOption>,
  ): Promise<DropdownOption | null> {
    await this.optionsRepository.update(optionId, data as never);
    return this.optionsRepository.findOne({ where: { id: optionId } });
  }

  async removeOption(optionId: string): Promise<void> {
    await this.optionsRepository.softDelete(optionId);
  }
}
