import { BadRequestException, Injectable, NotFoundException } from '@nestjs/common';
import { existsSync, readFileSync } from 'fs';
import { extname, isAbsolute, relative, resolve as resolvePath } from 'path';
import {
  fileManagerContentUrl,
  resolveProductImageUrl,
  resolveRootImageUrl,
} from '../common/file-manager-image.util';
import { PrismaService } from '../prisma/prisma.service';

type ProductSelectionQuery = {
  applicationId?: string;
  loadId?: string;
};

type WheelCollectionQuery = ProductSelectionQuery & {
  wheelSizeId?: string;
  wheelSizeCode?: string;
  wheelSizeInch?: string;
};

type SuitableWheelsQuery = ProductSelectionQuery & {
  wheelSizeInch?: string;
  wheelTypeCode?: string;
};

type MountingQuery = SuitableWheelsQuery & {
  wheelTagCode?: string;
};

type PlateQuery = MountingQuery & {
  mountCode?: string;
};

type ProductQuery = PlateQuery & {
  mountLoad?: string;
};

type ImageAsset = {
  relativePath: string;
  fullPath: string;
};

type TagRecord = {
  id: string;
  name: string;
  code: string;
  image?: string | null;
  status: string;
  orderId?: number | null;
};

@Injectable()
export class ProductSelectionService {
  constructor(private readonly prisma: PrismaService) {}

  async getWheelSizes(query: ProductSelectionQuery) {
    const context = await this.buildSelectionContext(query);
    const productWhere = await this.buildProductWhere(context);
    const groups = (await this.prisma.finalProduct.groupBy({
      by: ['inch'],
      where: {
        ...productWhere,
        inch: {
          not: null,
        },
      },
      _count: {
        _all: true,
      },
      orderBy: [
        {
          inch: 'asc',
        },
      ],
    } as any)) as any[];
    const inchValues = uniqueNumbers(groups.map((group) => Number(group.inch)))
      .filter((inch) => inch > 0 && inch <= 16)
      .sort((left, right) => left - right);
    const productCountByInch = new Map<number, number>();

    for (const group of groups) {
      const inch = Number(group.inch);
      if (!Number.isFinite(inch)) {
        continue;
      }

      productCountByInch.set(
        inch,
        (productCountByInch.get(inch) || 0) + this.groupCount(group),
      );
    }

    return {
      application: this.toPublicTag(context.application),
      load: this.toPublicLoad(context.load),
      items: inchValues.map((inch) => ({
        id: `inch-${formatInch(inch)}`,
        name: `${formatInch(inch)} Inch`,
        code: formatInch(inch),
        image: this.resolveInchImageUrl(inch),
        status: 'Active',
        orderId: inch,
        inch,
        productCount: productCountByInch.get(inch) || 0,
      })),
    };
  }

  async getWheelCollections(query: WheelCollectionQuery) {
    const context = await this.buildSelectionContext(query);
    const wheelSize = this.resolveWheelSize(query);
    const productWhere = await this.buildProductWhere(context, wheelSize.inch);
    const groups = (await this.prisma.finalProduct.groupBy({
      by: ['wheelType', 'wheelTypeSub'],
      where: {
        ...productWhere,
        wheelType: {
          not: null,
        },
      },
      _count: {
        _all: true,
      },
      orderBy: [
        {
          wheelType: 'asc',
        },
        {
          wheelTypeSub: 'asc',
        },
      ],
    } as any)) as any[];
    const wheelTypeCodes = unique(groups.map((group) => clean(group.wheelType)));
    const wheelTypeSubCodes = unique(groups.map((group) => clean(group.wheelTypeSub)));

    const [wheelTypes, wheelTypeSubs, sampleProducts] = await Promise.all([
      this.prisma.wheelType.findMany({
        where: {
          code: {
            in: wheelTypeCodes,
          },
          status: {
            equals: 'Active',
            mode: 'insensitive',
          },
        },
        orderBy: [{ orderId: 'asc' }, { name: 'asc' }],
      }),
      this.prisma.wheelTypeTag.findMany({
        where: {
          code: {
            in: wheelTypeSubCodes,
          },
          status: {
            equals: 'Active',
            mode: 'insensitive',
          },
        },
        orderBy: [{ orderId: 'asc' }, { name: 'asc' }],
      }),
      this.prisma.finalProduct.findMany({
        where: productWhere,
        orderBy: [{ code: 'asc' }],
        select: {
          code: true,
          inch: true,
          wheelType: true,
        },
      }),
    ]);
    const typeByCode = new Map(wheelTypes.map((item) => [item.code, item]));
    const subByCode = new Map(wheelTypeSubs.map((item) => [item.code, item]));
    const sampleImageByType = new Map<string, string>();

    for (const product of sampleProducts) {
      const wheelTypeCode = clean(product.wheelType);
      if (!wheelTypeCode || sampleImageByType.has(wheelTypeCode)) {
        continue;
      }

      sampleImageByType.set(
        wheelTypeCode,
        resolveProductImageUrl(product.code, product.inch),
      );
    }

    const subCountsByType = new Map<string, Map<string, number>>();
    for (const group of groups) {
      const wheelTypeCode = clean(group.wheelType);
      const subCode = clean(group.wheelTypeSub);
      if (!typeByCode.has(wheelTypeCode) || !subByCode.has(subCode)) {
        continue;
      }

      const subCounts = subCountsByType.get(wheelTypeCode) || new Map<string, number>();
      subCounts.set(subCode, (subCounts.get(subCode) || 0) + this.groupCount(group));
      subCountsByType.set(wheelTypeCode, subCounts);
    }

    return {
      application: this.toPublicTag(context.application),
      load: this.toPublicLoad(context.load),
      wheelSize: {
        ...wheelSize,
      },
      items: wheelTypes
        .filter((wheelType) => subCountsByType.has(wheelType.code))
        .map((wheelType) => {
          const subCounts = subCountsByType.get(wheelType.code) || new Map<string, number>();
          const subTypes = wheelTypeSubs
            .filter((subType) => subCounts.has(subType.code))
            .map((subType) => ({
              ...this.toPublicTag(subType),
              orderId: subType.orderId,
              productCount: subCounts.get(subType.code) || 0,
            }));

          return {
            ...this.toPublicTag(wheelType),
            orderId: wheelType.orderId,
            productCount: subTypes.reduce((total, subType) => total + subType.productCount, 0),
            sampleProductImage: sampleImageByType.get(wheelType.code) || '',
            subTypes,
          };
        }),
    };
  }

  async getSuitableWheels(query: SuitableWheelsQuery) {
    const context = await this.buildSelectionContext(query);
    const wheelSize = this.resolveWheelSize(query);
    const wheelType = await this.resolveWheelType(query.wheelTypeCode);
    const productWhere = await this.buildProductWhere(context, wheelSize.inch, {
      wheelType: wheelType.code,
    });
    const groups = (await this.prisma.finalProduct.groupBy({
      by: ['wheelTypeSub'],
      where: {
        ...productWhere,
        wheelTypeSub: {
          not: null,
        },
      },
      _count: {
        _all: true,
      },
      orderBy: [
        {
          wheelTypeSub: 'asc',
        },
      ],
    } as any)) as any[];
    const tagCodes = unique(groups.map((group) => clean(group.wheelTypeSub)));
    const [wheelTags, sampleProducts] = await Promise.all([
      this.prisma.wheelTypeTag.findMany({
        where: {
          code: {
            in: tagCodes,
          },
          status: {
            equals: 'Active',
            mode: 'insensitive',
          },
        },
        orderBy: [{ orderId: 'asc' }, { name: 'asc' }],
      }),
      this.prisma.finalProduct.findMany({
        where: productWhere,
        orderBy: [{ code: 'asc' }],
        select: {
          code: true,
          inch: true,
          wheelTypeSub: true,
        },
      }),
    ]);
    const productCountByCode = new Map<string, number>();
    const sampleImageByCode = new Map<string, string>();

    for (const group of groups) {
      const code = clean(group.wheelTypeSub);
      if (code) {
        productCountByCode.set(code, this.groupCount(group));
      }
    }

    for (const product of sampleProducts) {
      const code = clean(product.wheelTypeSub);
      if (!code || sampleImageByCode.has(code)) {
        continue;
      }

      sampleImageByCode.set(code, resolveProductImageUrl(product.code, product.inch));
    }

    return {
      application: this.toPublicTag(context.application),
      load: this.toPublicLoad(context.load),
      wheelSize,
      wheelType: {
        ...this.toPublicTag(wheelType),
        orderId: wheelType.orderId,
      },
      items: wheelTags.map((tag) => ({
        ...this.toPublicTag(tag),
        orderId: tag.orderId,
        productCount: productCountByCode.get(tag.code) || 0,
        sampleProductImage: sampleImageByCode.get(tag.code) || '',
      })),
    };
  }

  async getMountings(query: MountingQuery) {
    const context = await this.buildSelectionContext(query);
    const wheelSize = this.resolveWheelSize(query);
    const wheelType = await this.resolveWheelType(query.wheelTypeCode);
    const wheelTag = await this.resolveWheelTag(query.wheelTagCode);
    const productWhere = await this.buildProductWhere(context, wheelSize.inch, {
      wheelType: wheelType.code,
      wheelTypeSub: wheelTag.code,
    });
    const groups = (await this.prisma.finalProduct.groupBy({
      by: ['mountingType'],
      where: {
        ...productWhere,
        mountingType: {
          not: null,
        },
      },
      _count: {
        _all: true,
      },
      orderBy: [
        {
          mountingType: 'asc',
        },
      ],
    } as any)) as any[];
    const mountCodes = unique(groups.map((group) => clean(group.mountingType)));
    const [mountings, sampleProducts] = await Promise.all([
      this.prisma.mountingType.findMany({
        where: {
          code: {
            in: mountCodes,
          },
          status: {
            equals: 'Active',
            mode: 'insensitive',
          },
        },
        orderBy: [{ orderId: 'asc' }, { name: 'asc' }],
      }),
      this.prisma.finalProduct.findMany({
        where: productWhere,
        orderBy: [{ code: 'asc' }],
        select: {
          code: true,
          inch: true,
          mountingType: true,
          productDescription: true,
        },
      }),
    ]);
    const productCountByCode = new Map<string, number>();
    const sampleByCode = new Map<string, { image: string; detail: string }>();

    for (const group of groups) {
      const code = clean(group.mountingType);
      if (code) {
        productCountByCode.set(code, this.groupCount(group));
      }
    }

    for (const product of sampleProducts) {
      const code = clean(product.mountingType);
      if (!code || sampleByCode.has(code)) {
        continue;
      }

      sampleByCode.set(code, {
        image: resolveProductImageUrl(product.code, product.inch),
        detail: clean(product.productDescription),
      });
    }

    return {
      application: this.toPublicTag(context.application),
      load: this.toPublicLoad(context.load),
      wheelSize,
      wheelType: {
        ...this.toPublicTag(wheelType),
        orderId: wheelType.orderId,
      },
      selectedWheel: {
        ...this.toPublicTag(wheelTag),
        orderId: wheelTag.orderId,
        productCount: sampleProducts.length,
      },
      items: mountings.map((mounting) => {
        const sample = sampleByCode.get(mounting.code);

        return {
          ...this.toPublicTag(mounting),
          orderId: mounting.orderId,
          productCount: productCountByCode.get(mounting.code) || 0,
          sampleProductImage: sample?.image || '',
          details: sample?.detail || `${productCountByCode.get(mounting.code) || 0} matching product(s)`,
        };
      }),
    };
  }

  async getPlates(query: PlateQuery) {
    const context = await this.buildSelectionContext(query);
    const wheelSize = this.resolveWheelSize(query);
    const wheelType = await this.resolveWheelType(query.wheelTypeCode);
    const wheelTag = await this.resolveWheelTag(query.wheelTagCode);
    const mounting = await this.resolveMounting(query.mountCode);
    const productWhere = await this.buildProductWhere(context, wheelSize.inch, {
      wheelType: wheelType.code,
      wheelTypeSub: wheelTag.code,
      mountingType: mounting.code,
    });
    const products = await this.prisma.finalProduct.findMany({
      where: productWhere,
      orderBy: [{ yorkeLoad: 'asc' }, { yorkeCode: 'asc' }, { code: 'asc' }],
      select: {
        code: true,
        yorkeCode: true,
        yorkeLoad: true,
      },
    });

    if (!products.length) {
      return this.emptyPlateResponse(context, wheelSize, wheelType, wheelTag, mounting);
    }

    const productCodes = unique(products.map((product) => clean(product.code)));
    const setProducts = await this.prisma.setProduct.findMany({
      where: {
        productCode: {
          in: productCodes,
        },
      },
      select: {
        productCode: true,
        plateCode: true,
        plateName: true,
      },
    });
    const setProductByCode = new Map(setProducts.map((product) => [product.productCode, product]));
    const plateCodes = unique(setProducts.map((product) => clean(product.plateCode)));
    const plates = await this.prisma.plateMaster.findMany({
      where: {
        plateCode: {
          in: plateCodes,
        },
        mountingCode: mounting.code,
        status: {
          equals: 'Active',
          mode: 'insensitive',
        },
      },
      orderBy: [{ plateName: 'asc' }, { plateCode: 'asc' }],
    });
    const plateByCode = new Map(plates.map((plate) => [plate.plateCode, plate]));
    const grouped = new Map<
      string,
      {
        id: string;
        name: string;
        code: string;
        plateName: string;
        plateCode: string;
        yokeCode: string;
        displayCode: string;
        yokeLoad: string;
        status: string;
        productCount: number;
      }
    >();

    for (const product of products) {
      const setProduct = setProductByCode.get(product.code);
      const plate = setProduct ? plateByCode.get(setProduct.plateCode) : null;
      const plateCode = clean(plate?.plateCode || setProduct?.plateCode);
      const yokeCode = clean(product.yorkeCode || plate?.yokeCode);
      const displayCode = this.resolveYokeDisplayCode(yokeCode, mounting);
      const yokeLoad = clean(product.yorkeLoad);

      if (!plateCode || !yokeCode) {
        continue;
      }

      const key = [plateCode, displayCode, yokeLoad].join('|');
      const existing = grouped.get(key);
      if (existing) {
        existing.productCount += 1;
        continue;
      }

      grouped.set(key, {
        id: key,
        name: `${plate?.plateName || setProduct?.plateName || plateCode} / ${displayCode}`,
        code: plateCode,
        plateName: plate?.plateName || setProduct?.plateName || plateCode,
        plateCode,
        yokeCode,
        displayCode,
        yokeLoad,
        status: plate?.status || 'Active',
        productCount: 1,
      });
    }

    const items = [...grouped.values()].sort((left, right) => {
      const loadResult = this.numericValue(left.yokeLoad) - this.numericValue(right.yokeLoad);
      if (loadResult !== 0) {
        return loadResult;
      }

      return left.plateName.localeCompare(right.plateName, undefined, {
        numeric: true,
        sensitivity: 'base',
      });
    });

    if (!items.length) {
      return this.emptyPlateResponse(context, wheelSize, wheelType, wheelTag, mounting);
    }

    return {
      application: this.toPublicTag(context.application),
      load: this.toPublicLoad(context.load),
      wheelSize,
      wheelType: {
        ...this.toPublicTag(wheelType),
        orderId: wheelType.orderId,
      },
      selectedWheel: {
        ...this.toPublicTag(wheelTag),
        orderId: wheelTag.orderId,
      },
      mounting: {
        ...this.toPublicTag(mounting),
        orderId: mounting.orderId,
      },
      items,
      error: '',
    };
  }

  async getProducts(query: ProductQuery) {
    const context = await this.buildSelectionContext(query);
    const wheelSize = this.resolveWheelSize(query);
    const wheelType = await this.resolveWheelType(query.wheelTypeCode);
    const wheelTag = await this.resolveWheelTag(query.wheelTagCode);
    const mounting = await this.resolveMounting(query.mountCode);
    const mountLoad = clean(query.mountLoad);

    if (!mountLoad) {
      throw new BadRequestException('Yoke code is required.');
    }

    const productWhere = await this.buildProductWhere(context, wheelSize.inch, {
      wheelType: wheelType.code,
      wheelTypeSub: wheelTag.code,
      mountingType: mounting.code,
    });
    const products = await this.prisma.finalProduct.findMany({
      where: {
        ...productWhere,
        yorkeCode: mountLoad,
      },
      orderBy: [{ code: 'asc' }],
    });

    return {
      success: 1,
      app: this.toPublicTag(context.application),
      load: this.toPublicLoad(context.load),
      inch: wheelSize.inch,
      wtCode: wheelType.code,
      wheelCode: wheelTag.code,
      mountCode: mounting.code,
      mountLoad,
      products: products.map((product) => this.toPublicProduct(product)),
    };
  }

  async searchFinalProducts(search: string, pageSize = '20') {
    const term = clean(search);
    const take = Math.min(Math.max(Number.parseInt(pageSize, 10) || 20, 1), 50);

    if (!term) {
      return {
        success: 1,
        items: [],
      };
    }

    const products = await this.prisma.finalProduct.findMany({
      where: {
        status: {
          equals: 'Active',
          mode: 'insensitive',
        },
        OR: [
          { code: { contains: term, mode: 'insensitive' } },
          { productId: { contains: term, mode: 'insensitive' } },
          { uniqueCode: { contains: term, mode: 'insensitive' } },
          { productDescription: { contains: term, mode: 'insensitive' } },
          { wheelName: { contains: term, mode: 'insensitive' } },
          { wheelTypeSub: { contains: term, mode: 'insensitive' } },
        ],
      },
      orderBy: [{ code: 'asc' }],
      take,
    });

    return {
      success: 1,
      items: products.map((product) => this.toPublicProduct(product)),
    };
  }

  async getProductInformation(code: string) {
    const product = await this.findProductByCode(code);
    const specifications = await this.buildProductSpecifications(product);
    const publicProduct = this.toPublicProduct(product);
    const gallery = unique([
      publicProduct.image,
      resolveRootImageUrl(product.wheelTypeSub),
      resolveRootImageUrl(product.wheelType),
      resolveRootImageUrl(product.mountingType),
    ]);

    return {
      success: 1,
      product: {
        ...publicProduct,
        gallery,
        detailedDescription:
          clean(product.metaDescription) ||
          clean(product.pageTitle) ||
          clean(product.productDescription) ||
          'Detailed product information is not available for this product yet.',
        specifications,
      },
    };
  }

  async getProductBrochure(code: string) {
    const rawProduct = await this.findProductByCode(code);
    const specifications = await this.buildProductSpecifications(rawProduct);
    const publicProduct = this.toPublicProduct(rawProduct);
    const product = {
      ...publicProduct,
      detailedDescription:
        clean(rawProduct.metaDescription) ||
        clean(rawProduct.pageTitle) ||
        clean(rawProduct.wheelName) ||
        'Detailed product information is not available for this product yet.',
      specifications,
      seriesId: clean(rawProduct.yorkeCode),
      yokeLoad: clean(rawProduct.yorkeLoad),
      brochureCode: this.composeProductAssetCode(rawProduct) || rawProduct.code,
    };
    const imageAsset =
      this.findProductBrochureImageAsset(rawProduct) ||
      imageAssetFromContentUrl(publicProduct.image);
    const commonAsset = this.findRootJpegAsset('common');

    return {
      filename: `${safeFileName(product.code || 'product')}c.pdf`,
      buffer: createBrochurePdf(product, imageAsset, commonAsset),
    };
  }

  private async buildSelectionContext(query: ProductSelectionQuery) {
    if (!clean(query.loadId)) {
      throw new BadRequestException('Load per wheel is required.');
    }

    const [application, load] = await Promise.all([
      clean(query.applicationId)
        ? this.prisma.application.findUnique({
            where: {
              id: clean(query.applicationId),
            },
          })
        : null,
      this.prisma.loadCarryCapacity.findUnique({
        where: {
          id: clean(query.loadId),
        },
      }),
    ]);

    if (clean(query.applicationId) && !application) {
      throw new NotFoundException('Application was not found.');
    }

    if (!load) {
      throw new NotFoundException('Load per wheel was not found.');
    }

    return {
      application,
      load,
      loadCodes: await this.resolveLoadCodesFrom(load),
    };
  }

  private resolveWheelSize(query: WheelCollectionQuery) {
    const rawValue = clean(query.wheelSizeInch) || clean(query.wheelSizeCode) || clean(query.wheelSizeId);
    const inch = Number.parseFloat(rawValue.replace(/^inch-/i, ''));

    if (Number.isFinite(inch) && inch > 0) {
      return {
        id: `inch-${formatInch(inch)}`,
        name: `${formatInch(inch)} Inch`,
        code: formatInch(inch),
        image: this.resolveInchImageUrl(inch),
        status: 'Active',
        orderId: inch,
        inch,
      };
    }

    throw new BadRequestException('Wheel size inch is required.');
  }

  private async resolveWheelType(code?: string) {
    const wheelTypeCode = clean(code);
    if (!wheelTypeCode) {
      throw new BadRequestException('Wheel collection is required.');
    }

    const wheelType = await this.prisma.wheelType.findFirst({
      where: {
        code: wheelTypeCode,
        status: {
          equals: 'Active',
          mode: 'insensitive',
        },
      },
    });

    if (!wheelType) {
      throw new NotFoundException('Wheel collection was not found.');
    }

    return wheelType;
  }

  private async resolveWheelTag(code?: string) {
    const wheelTagCode = clean(code);
    if (!wheelTagCode) {
      throw new BadRequestException('Suitable wheel is required.');
    }

    const wheelTag = await this.prisma.wheelTypeTag.findFirst({
      where: {
        code: wheelTagCode,
        status: {
          equals: 'Active',
          mode: 'insensitive',
        },
      },
    });

    if (!wheelTag) {
      throw new NotFoundException('Suitable wheel was not found.');
    }

    return wheelTag;
  }

  private async resolveMounting(code?: string) {
    const mountCode = clean(code);
    if (!mountCode) {
      throw new BadRequestException('Mounting is required.');
    }

    const mounting = await this.prisma.mountingType.findFirst({
      where: {
        code: mountCode,
        status: {
          equals: 'Active',
          mode: 'insensitive',
        },
      },
    });

    if (!mounting) {
      throw new NotFoundException('Mounting was not found.');
    }

    return mounting;
  }

  private async resolveLoadCodesFrom(load: TagRecord) {
    const activeWhere = {
      status: {
        equals: 'Active',
        mode: 'insensitive',
      },
    } as const;
    const allLoads = await this.prisma.loadCarryCapacity.findMany({
      where: activeWhere,
      orderBy: [{ orderId: 'asc' }, { name: 'asc' }],
    });
    const selectedOrder = load.orderId ?? this.numericValue(load.name);

    return allLoads
      .filter((item) => {
        const order = item.orderId ?? this.numericValue(item.name);
        return order >= selectedOrder;
      })
      .map((item) => item.code);
  }

  private async buildProductWhere(
    context: {
      application: TagRecord | null;
      load: TagRecord;
      loadCodes: string[];
    },
    productInch?: number,
    filters: {
      wheelType?: string;
      wheelTypeSub?: string;
      mountingType?: string;
    } = {},
  ) {
    const and: any[] = [
      {
        status: {
          equals: 'Active',
          mode: 'insensitive',
        },
      },
      {
        loadCarryingCapacity: {
          in: context.loadCodes.length ? context.loadCodes : [context.load.code],
        },
      },
    ];

    if (typeof productInch === 'number' && Number.isFinite(productInch)) {
      and.push({
        inch: productInch,
      });
    }

    if (clean(filters.wheelType)) {
      and.push({
        wheelType: clean(filters.wheelType),
      });
    }

    if (clean(filters.wheelTypeSub)) {
      and.push({
        wheelTypeSub: clean(filters.wheelTypeSub),
      });
    }

    if (clean(filters.mountingType)) {
      and.push({
        mountingType: clean(filters.mountingType),
      });
    }

    if (context.application && (await this.hasApplicationProducts(context.application))) {
      and.push({
        application: {
          in: [context.application.code, context.application.name],
        },
      });
    }

    return {
      AND: and,
    };
  }

  private async hasApplicationProducts(application: TagRecord) {
    const count = await this.prisma.finalProduct.count({
      where: {
        status: {
          equals: 'Active',
          mode: 'insensitive',
        },
        application: {
          in: [application.code, application.name],
        },
      },
    });

    return count > 0;
  }

  private async findProductByCode(code: string) {
    const productCode = clean(code);
    if (!productCode) {
      throw new BadRequestException('Product code is required.');
    }

    const product = await this.prisma.finalProduct.findUnique({
      where: {
        code: productCode,
      },
    });

    if (!product) {
      throw new NotFoundException('Product was not found.');
    }

    return product;
  }

  private toPublicProduct(product: any) {
    const productName = clean(product.productDescription);
    const wheelName = clean(product.wheelName);

    return {
      id: clean(product.productId) || product.id,
      code: product.code,
      name: productName || wheelName || product.code,
      description:
        wheelName ||
        'No matching product description found for this product.',
      image: this.resolveFinalProductImage(product),
      price: null,
      productTag: clean(product.wheelTypeSub) || clean(product.uniqueCode),
    };
  }

  private resolveFinalProductImage(product: any) {
    const exactProductImage = this.findExactProductCodeImageAsset(product);
    if (exactProductImage) {
      return fileManagerContentUrl(exactProductImage.relativePath);
    }

    const asset = this.findProductImageAsset(product);
    if (asset) {
      return fileManagerContentUrl(asset.relativePath);
    }

    const composedCode = this.composeProductAssetCode(product);
    const composedImage = resolveRootImageUrl(composedCode);
    if (composedImage) {
      return composedImage;
    }

    return resolveProductImageUrl(product.code, product.inch);
  }

  private findExactProductCodeImageAsset(product: any): ImageAsset | null {
    const folder = formatInch(Number(product.inch || 0));
    const code = clean(product.code);
    if (!folder || !code) {
      return null;
    }

    for (const extension of ['.png', '.PNG']) {
      const asset = fileManagerAsset(`${folder}/${code}${extension}`);
      if (asset) {
        return asset;
      }
    }

    return null;
  }

  private findProductImageAsset(product: any): ImageAsset | null {
    const folder = formatInch(Number(product.inch || 0));
    const bases = unique([
      this.composeProductAssetCode(product),
      clean(product.uniqueCode),
      clean(product.code),
      clean(product.productId),
    ]);
    const folders = unique(['', folder]);

    for (const imageFolder of folders) {
      for (const base of bases) {
        for (const extension of ['.jpg', '.jpeg', '.png', '.JPG', '.JPEG', '.PNG']) {
          const relativePath = [imageFolder, `${base}${extension}`].filter(Boolean).join('/');
          const asset = fileManagerAsset(relativePath);
          if (asset) {
            return asset;
          }
        }
      }
    }

    return null;
  }

  private findProductBrochureImageAsset(product: any): ImageAsset | null {
    const composedCode = this.composeProductAssetCode(product);
    for (const extension of ['.jpg', '.jpeg', '.JPG', '.JPEG']) {
      const asset = fileManagerAsset(`${composedCode}${extension}`);
      if (asset) {
        return asset;
      }
    }

    return this.findProductImageAsset(product);
  }

  private findRootJpegAsset(base: string): ImageAsset | null {
    const cleanBase = clean(base);
    for (const extension of ['.jpg', '.jpeg', '.JPG', '.JPEG']) {
      const asset = fileManagerAsset(`${cleanBase}${extension}`);
      if (asset) {
        return asset;
      }
    }

    return null;
  }

  private composeProductAssetCode(product: any) {
    return clean(product.uniqueCode) || [
      clean(product.wheelSize),
      clean(product.fittingType),
      clean(product.yorkeCode),
      clean(product.headerType),
    ].join('');
  }

  private async buildProductSpecifications(product: any) {
    const rows = [
      { label: 'Product ID', value: clean(product.productId) || product.id },
      { label: 'Product Code', value: product.code },
      { label: 'Wheel Type', value: product.wheelType, model: 'wheelType' },
      { label: 'Wheel Type Tag', value: product.wheelTypeSub, model: 'wheelTypeTag' },
      { label: 'Load Carrying Capacity', value: product.loadCarryingCapacity, model: 'loadCarryCapacity' },
      { label: 'Wheel Size', value: product.wheelSize, model: 'wheelSize' },
      { label: 'Wheel Inch', value: product.inch ? `${formatInch(Number(product.inch))} Inch` : '' },
      { label: 'Wheel Color', value: product.wheelColor, model: 'wheelColor' },
      { label: 'Bearing Type', value: product.bearingType, model: 'bearingType' },
      { label: 'Dust Cover', value: product.dustCoverOnWheel, model: 'dustCoverType' },
      { label: 'Fitting Size', value: product.fittingType, model: 'fittingSize' },
      { label: 'Body Type', value: product.bodyType, model: 'bodyType' },
      { label: 'Finish Type', value: product.finishType, model: 'finishType' },
      { label: 'Bearing In Frame', value: product.bearingInFrame, model: 'bearingInFrameType' },
      { label: 'Braking System', value: product.brakingSystem, model: 'brakingSystem' },
      { label: 'Frame Color', value: product.frameColor, model: 'frameColor' },
      { label: 'Header Type', value: product.headerType, model: 'headerType' },
      { label: 'Mounting Type', value: product.mountingType, model: 'mountingType' },
      { label: 'Application', value: product.application },
      { label: 'Yoke Code', value: product.yorkeCode },
      { label: 'Yoke Load', value: product.yorkeLoad },
    ];

    return Promise.all(
      rows
        .filter((row) => clean(row.value))
        .map(async (row) => ({
          label: row.label,
          code: clean(row.value),
          value: row.model
            ? await this.resolveSpecValue(row.model, row.value)
            : clean(row.value),
        })),
    );
  }

  private async resolveSpecValue(modelName: string, code: unknown) {
    const value = clean(code);
    if (!value) {
      return '';
    }

    const delegate = (this.prisma as any)[modelName];
    if (!delegate?.findFirst) {
      return value;
    }

    const record = await delegate.findFirst({
      where: {
        code: value,
      },
    });

    return clean(record?.name) || value;
  }

  private toPublicTag(tag: TagRecord | null) {
    if (!tag) {
      return null;
    }

    return {
      id: tag.id,
      name: tag.name,
      code: tag.code,
      image: resolveRootImageUrl(tag.code, tag.name, tag.image),
      status: tag.status,
    };
  }

  private toPublicLoad(load: TagRecord) {
    const publicLoad = this.toPublicTag(load);

    return {
      ...publicLoad,
      orderId: load.orderId,
      displayName: load.name.replace(/\s*kg\b/gi, '').trim(),
    };
  }

  private numericValue(value: unknown) {
    const parsed = Number.parseFloat(clean(value).replace(/[^\d.]+/g, ''));
    return Number.isFinite(parsed) ? parsed : Number.MAX_SAFE_INTEGER;
  }

  private resolveYokeDisplayCode(yokeCode: string, mounting: TagRecord) {
    if (!yokeCode) {
      return '';
    }

    const mountingSuffix = this.mountingImageSuffix(mounting);
    return mountingSuffix ? `${yokeCode}-${mountingSuffix}` : yokeCode;
  }

  private mountingImageSuffix(mounting: TagRecord) {
    if (mounting.orderId === null || mounting.orderId === undefined) {
      return '';
    }

    const suffix = Number(mounting.orderId);
    return Number.isFinite(suffix) && suffix > 0 ? String(Math.trunc(suffix)) : '';
  }

  private groupCount(group: any) {
    return Number(group?._count?._all || 0);
  }

  private resolveInchImageUrl(inch: number) {
    const label = formatInch(inch);
    const exactCandidates = [`${label} inch`, `${label} Inch`, `${label} INCH`];

    for (const candidate of exactCandidates) {
      const image = resolveRootImageUrl(candidate);
      if (image) {
        return image;
      }
    }

    return '';
  }

  private emptyPlateResponse(
    context: {
      application: TagRecord | null;
      load: TagRecord;
    },
    wheelSize: any,
    wheelType: TagRecord,
    wheelTag: TagRecord,
    mounting: TagRecord,
  ) {
    return {
      application: this.toPublicTag(context.application),
      load: this.toPublicLoad(context.load),
      wheelSize,
      wheelType: {
        ...this.toPublicTag(wheelType),
        orderId: wheelType.orderId,
      },
      selectedWheel: {
        ...this.toPublicTag(wheelTag),
        orderId: wheelTag.orderId,
      },
      mounting: {
        ...this.toPublicTag(mounting),
        orderId: mounting.orderId,
      },
      items: [],
      error: 'No yoke size found. Please contact administrator.',
    };
  }
}

function unique(values: string[]) {
  return [...new Set(values.filter(Boolean))];
}

function uniqueNumbers(values: number[]) {
  return [...new Set(values.filter((value) => Number.isFinite(value)))];
}

function formatInch(value: number) {
  return Number.isInteger(value) ? String(value) : String(value).replace(/\.0+$/, '');
}

const fileManagerRoot = resolvePath(process.cwd(), 'storage', 'file-manager');

type PdfImage = {
  name: string;
  data: Buffer;
  width: number;
  height: number;
};

function safeFileManagerPath(relativePath: string) {
  const fullPath = resolvePath(fileManagerRoot, relativePath);
  const distance = relative(fileManagerRoot, fullPath);
  if (distance.startsWith('..') || isAbsolute(distance)) {
    return '';
  }

  return fullPath;
}

function fileManagerAsset(relativePath: string): ImageAsset | null {
  const normalizedPath = clean(relativePath).replace(/\\/g, '/');
  if (!normalizedPath) {
    return null;
  }

  const fullPath = safeFileManagerPath(normalizedPath);
  if (!fullPath || !existsSync(fullPath)) {
    return null;
  }

  return {
    relativePath: normalizedPath,
    fullPath,
  };
}

function imageAssetFromContentUrl(value: string): ImageAsset | null {
  const text = clean(value);
  const marker = '/api/file-manager/content?';
  const markerIndex = text.indexOf(marker);
  if (markerIndex < 0) {
    return null;
  }

  try {
    const params = new URLSearchParams(text.slice(markerIndex + marker.length));
    const relativePath = clean(params.get('path')).replace(/\\/g, '/');
    const fullPath = safeFileManagerPath(relativePath);
    if (!fullPath || !existsSync(fullPath)) {
      return null;
    }

    return {
      relativePath,
      fullPath,
    };
  } catch {
    return null;
  }
}

function loadPdfImage(fullPath: string, name = 'Im1'): PdfImage | null {
  const extension = extname(fullPath).toLowerCase();
  if (!['.jpg', '.jpeg'].includes(extension) || !existsSync(fullPath)) {
    return null;
  }

  const data = readFileSync(fullPath);
  const size = readJpegSize(data);
  if (!size) {
    return null;
  }

  return {
    name,
    data,
    width: size.width,
    height: size.height,
  };
}

function readJpegSize(data: Buffer) {
  let offset = 2;
  while (offset < data.length) {
    if (data[offset] !== 0xff) {
      offset += 1;
      continue;
    }

    const marker = data[offset + 1];
    const length = data.readUInt16BE(offset + 2);
    if ([0xc0, 0xc1, 0xc2, 0xc3].includes(marker)) {
      return {
        height: data.readUInt16BE(offset + 5),
        width: data.readUInt16BE(offset + 7),
      };
    }

    offset += 2 + length;
  }

  return null;
}

function createBrochurePdf(
  product: any,
  imageAsset: ImageAsset | null,
  commonAsset: ImageAsset | null,
) {
  const image = imageAsset ? loadPdfImage(imageAsset.fullPath, 'Im1') : null;
  const commonImage = commonAsset ? loadPdfImage(commonAsset.fullPath, 'Im2') : null;
  const images = [image, commonImage].filter(Boolean) as PdfImage[];
  const contentStreams = [
    buildBrochureCoverContent(product, image),
    buildBrochureImagePageContent('Product View', image),
    buildBrochureImagePageContent('Common Information', commonImage),
  ];

  return createPdfDocument(contentStreams, images);
}

function createPdfDocument(contentStreams: string[], images: PdfImage[]) {
  const objects: string[] = [
    '<< /Type /Catalog /Pages 2 0 R >>',
    '',
    '<< /Type /Font /Subtype /Type1 /BaseFont /Helvetica >>',
    '<< /Type /Font /Subtype /Type1 /BaseFont /Helvetica-Bold >>',
  ];
  const imageRefs = new Map<string, number>();

  for (const image of images) {
    const ref = objects.length + 1;
    imageRefs.set(image.name, ref);
    objects.push(
      [
        `<< /Type /XObject /Subtype /Image /Width ${image.width} /Height ${image.height}`,
        `/ColorSpace /DeviceRGB /BitsPerComponent 8 /Filter /DCTDecode /Length ${image.data.length} >>`,
        'stream',
        image.data.toString('binary'),
        'endstream',
      ].join('\n'),
    );
  }

  const pageRefs: string[] = [];
  const xObjectResources = images.length
    ? `/XObject << ${images.map((image) => `/${image.name} ${imageRefs.get(image.name)} 0 R`).join(' ')} >>`
    : '';

  for (const content of contentStreams) {
    const contentRef = objects.length + 1;
    objects.push(
      `<< /Length ${Buffer.byteLength(content, 'latin1')} >>\nstream\n${content}\nendstream`,
    );
    const pageRef = objects.length + 1;
    objects.push(
      `<< /Type /Page /Parent 2 0 R /MediaBox [0 0 842 595] /Resources << /Font << /F1 3 0 R /F2 4 0 R >> ${xObjectResources} >> /Contents ${contentRef} 0 R >>`,
    );
    pageRefs.push(`${pageRef} 0 R`);
  }

  objects[1] = `<< /Type /Pages /Count ${pageRefs.length} /Kids [${pageRefs.join(' ')}] >>`;

  let pdf = '%PDF-1.4\n';
  const offsets = [0];

  objects.forEach((object, index) => {
    offsets[index + 1] = Buffer.byteLength(pdf, 'latin1');
    pdf += `${index + 1} 0 obj\n${object}\nendobj\n`;
  });

  const xrefOffset = Buffer.byteLength(pdf, 'latin1');
  pdf += `xref\n0 ${objects.length + 1}\n`;
  pdf += '0000000000 65535 f \n';
  for (let index = 1; index <= objects.length; index += 1) {
    pdf += `${String(offsets[index]).padStart(10, '0')} 00000 n \n`;
  }
  pdf += `trailer\n<< /Size ${objects.length + 1} /Root 1 0 R >>\nstartxref\n${xrefOffset}\n%%EOF`;

  return Buffer.from(pdf, 'binary');
}

function buildBrochureCoverContent(product: any, image: PdfImage | null) {
  const spec = specMap(product.specifications);
  const fitting = spec.get('Fitting Size') || '';
  const wheelType = spec.get('Wheel Type') || '';
  const load = spec.get('Load Carrying Capacity') || '';
  const staticLoad = product.yokeLoad ? `${Number(product.yokeLoad) * 2.5 || ''} kg` : '';
  const code = product.brochureCode || product.code;
  const commands = [
    'q 1 1 1 rg 20 20 802 555 re f Q',
    'q 0 0 0 RG 1 w 20 20 802 555 re S Q',
    text('STARLINE', 42, 522, 22, true),
    text(`Product ID:${product.code}`, 42, 466, 16, true, '0 0 1 rg'),
    text(`Series ID:${product.seriesId || 'Not specified'}`, 42, 444, 13, true),
    ...multilineText(`${fitting} WITH ${wheelType}`, 42, 412, 15, true, 42),
    text(`Dynamic Load Carrying Capacity - ${load || 'Not specified'}`, 42, 360, 12, true),
    text(`Static Load Carrying Capacity - ${staticLoad || 'Not specified'}`, 42, 342, 12, true),
    text('Castor:', 42, 300, 15, true),
    ...tableRows(50, 276, 136, 214, [
      ['Fitting Type :', fitting],
      ['Body Type:', spec.get('Body Type') || ''],
      ['Finish Type:', spec.get('Finish Type') || ''],
      ['Bearing In Frame:', spec.get('Bearing In Frame') || ''],
      ['Breaking System :', spec.get('Braking System') || ''],
      ['Frame Color :', spec.get('Frame Color') || ''],
    ]),
    text('Wheel:', 42, 154, 15, true),
    ...tableRows(50, 130, 120, 255, [
      ['Wheel Size :', spec.get('Wheel Size') || ''],
      ['Wheel Type:', wheelType],
      ['Wheel Color:', spec.get('Wheel Color') || ''],
      ['Bearing Type:', spec.get('Bearing Type') || ''],
      ['Dust Cover On Wheel :', spec.get('Dust Cover') || ''],
    ]),
    text(`Code :${code}`, 48, 42, 12, true),
  ];

  if (image) {
    commands.push(drawImage(image, 468, 300, 338, 235));
  } else {
    commands.push('q 0.93 0.96 1 rg 468 300 338 235 re f Q');
    commands.push(text('Product image', 585, 410, 16, true));
  }

  return commands.join('\n');
}

function buildBrochureImagePageContent(title: string, image: PdfImage | null) {
  const commands = ['q 1 1 1 rg 0 0 842 595 re f Q'];
  if (image) {
    commands.push(drawImageCover(image, 34, 14, 774, 548));
  } else {
    commands.push('q 0.93 0.96 1 rg 34 14 774 548 re f Q');
    commands.push(text(title, 360, 300, 22, true));
  }
  return commands.join('\n');
}

function specMap(specifications: any[]) {
  return new Map<string, string>(
    specifications.map((spec) => [clean(spec.label), clean(spec.value)]),
  );
}

function tableRows(
  x: number,
  startY: number,
  labelWidth: number,
  valueWidth: number,
  rows: string[][],
  rowHeight = 19,
) {
  const commands: string[] = [];
  rows.forEach(([label, value], index) => {
    const y = startY - index * rowHeight;
    commands.push(`q 0 0 0 RG 0.6 w ${x} ${y - 6} ${labelWidth + valueWidth} ${rowHeight} re S Q`);
    commands.push(`q 0 0 0 RG 0.4 w ${x + labelWidth} ${y - 6} m ${x + labelWidth} ${y - 6 + rowHeight} l S Q`);
    commands.push(text(label, x + 5, y, 9, false));
    commands.push(...multilineText(value || 'Not specified', x + labelWidth + 7, y, 9, true, 42));
  });
  return commands;
}

function text(value: string, x: number, y: number, size = 11, bold = false, color = '0 0 0 rg') {
  return [
    'BT',
    color,
    `/${bold ? 'F2' : 'F1'} ${size} Tf`,
    `1 0 0 1 ${x} ${y} Tm`,
    `(${escapePdfText(value)}) Tj`,
    'ET',
  ].join('\n');
}

function multilineText(
  value: string,
  x: number,
  y: number,
  size = 11,
  bold = false,
  maxLength = 70,
) {
  return wrapPdfLine(value, maxLength).slice(0, 3).map((line, index) =>
    text(line, x, y - index * (size + 3), size, bold),
  );
}

function drawImage(image: PdfImage, x: number, y: number, width: number, height: number) {
  return `q\n${width} 0 0 ${height} ${x} ${y} cm\n/${image.name} Do\nQ`;
}

function drawImageCover(image: PdfImage, x: number, y: number, width: number, height: number) {
  const scale = Math.min(width / image.width, height / image.height);
  const drawWidth = image.width * scale;
  const drawHeight = image.height * scale;
  return drawImage(
    image,
    x + (width - drawWidth) / 2,
    y + (height - drawHeight) / 2,
    drawWidth,
    drawHeight,
  );
}

function wrapPdfLine(line: string, maxLength = 110) {
  const text = clean(line);
  if (!text) {
    return [''];
  }

  const words = text.split(/\s+/);
  const lines: string[] = [];
  let current = '';

  for (const word of words) {
    const next = current ? `${current} ${word}` : word;
    if (next.length > maxLength && current) {
      lines.push(current);
      current = word;
    } else {
      current = next;
    }
  }

  if (current) {
    lines.push(current);
  }

  return lines;
}

function escapePdfText(value: string) {
  return clean(value)
    .replace(/[^\x20-\x7E]/g, ' ')
    .replace(/\\/g, '\\\\')
    .replace(/\(/g, '\\(')
    .replace(/\)/g, '\\)');
}

function safeFileName(value: string) {
  return clean(value).replace(/[^a-z0-9_-]+/gi, '-').replace(/^-+|-+$/g, '') || 'product';
}

function clean(value: unknown) {
  return String(value ?? '').trim();
}
