import { Injectable, BadRequestException, OnModuleInit } from '@nestjs/common';
import { CatalogEntityKind } from '@prisma/client';
import { PrismaService } from '../../../prisma/prisma.service';
import {
  CatalogLabelService,
  CatalogLocale,
  normalizeCatalogLocale,
} from '../catalog/catalog-label.service';

export type ProsthesisTypeCatalogEntry = {
  code: string;
  sortOrder: number;
  label: string;
};

@Injectable()
export class ProsthesisCatalogService implements OnModuleInit {
  private loaded = false;
  private byCode = new Map<string, { sortOrder: number }>();

  constructor(
    private readonly prisma: PrismaService,
    private readonly catalogLabels: CatalogLabelService,
  ) {}

  async onModuleInit() {
    await this.refresh();
  }

  async refresh(): Promise<void> {
    const rows = await this.prisma.prosthesisType.findMany({
      where: { isActive: true },
      orderBy: [{ sortOrder: 'asc' }, { code: 'asc' }],
      select: { code: true, sortOrder: true },
    });

    this.byCode = new Map(rows.map((row) => [row.code, { sortOrder: row.sortOrder }]));
    this.loaded = true;
  }

  async list(localeInput?: string | null): Promise<ProsthesisTypeCatalogEntry[]> {
    this.ensureLoaded();
    const locale = normalizeCatalogLocale(localeInput);
    const codes = [...this.byCode.keys()];
    const labels = await this.catalogLabels.resolveLabels(
      CatalogEntityKind.PROSTHESIS_TYPE,
      codes,
      locale,
    );

    return codes
      .map((code) => ({
        code,
        sortOrder: this.byCode.get(code)!.sortOrder,
        label: labels.get(code) ?? code,
      }))
      .sort((a, b) => a.sortOrder - b.sortOrder || a.code.localeCompare(b.code));
  }

  assertKnownProsthesisType(code: string): void {
    this.ensureLoaded();
    if (!this.byCode.has(code)) {
      throw new BadRequestException(`Unknown prosthesis type: ${code}`);
    }
  }

  async getStepCodesForProsthesisType(prosthesisTypeCode: string): Promise<string[]> {
    const type = await this.prisma.prosthesisType.findUnique({
      where: { code: prosthesisTypeCode },
      select: {
        steps: {
          orderBy: { stepOrder: 'asc' },
          select: { labWorkflowStep: { select: { code: true } } },
        },
      },
    });

    if (!type) {
      return [];
    }

    return type.steps.map((s) => s.labWorkflowStep.code);
  }

  async resolveStepLabels(stepCodes: string[], locale: CatalogLocale): Promise<Map<string, string>> {
    return this.catalogLabels.resolveLabels(
      CatalogEntityKind.LAB_WORKFLOW_STEP,
      stepCodes,
      locale,
    );
  }

  private ensureLoaded() {
    if (!this.loaded) {
      throw new Error('Prosthesis catalog is not loaded yet');
    }
  }
}
