import {
  normalizeDocumentSequenceProductType,
  resolveDocumentSequenceProductTypeCode
} from './config';

export interface DocumentSequenceProductTypeLookupOption {
  id: string;
  code: string;
  label?: string | null;
}

export type DocumentSequenceProductTypeMatch =
  | 'generic'
  | 'option-id'
  | 'option-code'
  | 'sequence-alias';

export interface DocumentSequenceProductTypeResolution {
  productType: string | null;
  matchedBy: DocumentSequenceProductTypeMatch;
  normalizedRequestedProductType: string | null;
}

function resolveProductTypeOptionByCode(
  options: ReadonlyArray<DocumentSequenceProductTypeLookupOption>,
  requestedProductType: string
):
  | {
      productType: string;
      matchedBy: Exclude<DocumentSequenceProductTypeMatch, 'generic' | 'option-id'>;
    }
  | null {
  const normalizedRequestedProductType =
    normalizeDocumentSequenceProductType(requestedProductType);

  const byCode = options.find(
    (option) =>
      normalizeDocumentSequenceProductType(option.code) === normalizedRequestedProductType
  );
  if (byCode) {
    return {
      productType: normalizeDocumentSequenceProductType(byCode.code),
      matchedBy: 'option-code'
    };
  }

  const requestedSequenceCode =
    resolveDocumentSequenceProductTypeCode(normalizedRequestedProductType);
  if (!requestedSequenceCode) {
    return null;
  }

  const bySequenceAlias = options.find(
    (option) =>
      resolveDocumentSequenceProductTypeCode(option.code) === requestedSequenceCode
  );
  if (!bySequenceAlias) {
    return null;
  }

  return {
    productType: normalizeDocumentSequenceProductType(bySequenceAlias.code),
    matchedBy: 'sequence-alias'
  };
}

export function resolveDocumentSequenceProductTypeInput(input: {
  documentType: string;
  productType?: string | null;
  options: ReadonlyArray<DocumentSequenceProductTypeLookupOption>;
  referenceOptions?: ReadonlyArray<DocumentSequenceProductTypeLookupOption>;
}): DocumentSequenceProductTypeResolution {
  const normalizedDocumentType = input.documentType.trim();
  const requestedProductType = input.productType?.trim() ?? null;

  if (normalizedDocumentType !== 'quotation') {
    return {
      productType: requestedProductType
        ? normalizeDocumentSequenceProductType(requestedProductType)
        : 'all',
      matchedBy: 'generic',
      normalizedRequestedProductType: requestedProductType
        ? normalizeDocumentSequenceProductType(requestedProductType)
        : null
    };
  }

  if (!requestedProductType) {
    return {
      productType: null,
      matchedBy: 'generic',
      normalizedRequestedProductType: null
    };
  }

  const normalizedRequestedProductType =
    normalizeDocumentSequenceProductType(requestedProductType);

  const byId = input.options.find((option) => option.id === requestedProductType);
  if (byId) {
    return {
      productType: normalizeDocumentSequenceProductType(byId.code),
      matchedBy: 'option-id',
      normalizedRequestedProductType
    };
  }

  const directCodeMatch = resolveProductTypeOptionByCode(
    input.options,
    requestedProductType
  );
  if (directCodeMatch) {
    return {
      productType: directCodeMatch.productType,
      matchedBy: directCodeMatch.matchedBy,
      normalizedRequestedProductType
    };
  }

  const referenceOptionById = input.referenceOptions?.find(
    (option) => option.id === requestedProductType
  );
  if (referenceOptionById) {
    const translatedMatch = resolveProductTypeOptionByCode(
      input.options,
      referenceOptionById.code
    );

    return {
      productType: translatedMatch?.productType ?? null,
      matchedBy: 'option-id',
      normalizedRequestedProductType
    };
  }

  const translatedCode = input.referenceOptions?.find(
    (option) =>
      normalizeDocumentSequenceProductType(option.code) === normalizedRequestedProductType
  )?.code;
  if (!translatedCode) {
    return {
      productType: null,
      matchedBy: 'generic',
      normalizedRequestedProductType
    };
  }

  const translatedMatch = resolveProductTypeOptionByCode(input.options, translatedCode);
  return {
    productType: translatedMatch?.productType ?? null,
    matchedBy: translatedMatch?.matchedBy ?? 'generic',
    normalizedRequestedProductType
  };
}
