import type {
  PlantIdentificationInput,
  PlantScanPhoto,
  PlantScanPhotoRole,
} from './types';

const fallbackPhotoRoles: PlantScanPhotoRole[] = ['whole', 'leaf', 'flower'];
const validPhotoRoles = new Set<PlantScanPhotoRole>([
  'whole',
  'leaf',
  'flower',
  'fruit',
  'bark',
  'cutting',
  'plant',
  'habitat',
]);

function normalizeDimension(value: unknown): number | undefined {
  return typeof value === 'number' && Number.isFinite(value) && value > 0
    ? value
    : undefined;
}


function normalizePhotoUri(value: unknown): string | undefined {
  if (typeof value !== 'string') return undefined;

  // Preserve spaces in file/content URIs. Strip control characters instead of
  // collapsing all whitespace, which could corrupt a base64 data URI.
  const normalized = value.replace(/[\u0000-\u001F\u007F]/g, '').trim();
  return normalized || undefined;
}

function normalizePhotoRole(value: unknown): PlantScanPhotoRole {
  return typeof value === 'string' && validPhotoRoles.has(value as PlantScanPhotoRole)
    ? value as PlantScanPhotoRole
    : 'whole';
}

export function normalizeOptionalText(value: unknown, maxLength = 500): string | undefined {
  if (typeof value !== 'string') return undefined;

  const normalized = value
    .replace(/[\u0000-\u001F\u007F]/g, ' ')
    .replace(/\s+/g, ' ')
    .trim();

  if (!normalized) return undefined;
  return normalized.slice(0, maxLength);
}

function normalizePhoto(value: unknown): PlantScanPhoto | null {
  if (!value || typeof value !== 'object' || Array.isArray(value)) return null;

  const record = value as Partial<PlantScanPhoto>;
  const uri = normalizePhotoUri(record.uri);
  if (!uri) return null;

  const width = normalizeDimension(record.width);
  const height = normalizeDimension(record.height);

  return {
    role: normalizePhotoRole(record.role),
    uri,
    ...(width ? { width } : {}),
    ...(height ? { height } : {}),
  };
}

function photosFromUris(values: readonly unknown[]): PlantScanPhoto[] {
  return values.flatMap((value, index) => {
    const uri = normalizePhotoUri(value);
    if (!uri) return [];

    return [{
      role: fallbackPhotoRoles[index] || 'whole',
      uri,
    }];
  });
}

export function getPlantScanPhotos(input: PlantIdentificationInput): PlantScanPhoto[] {
  const structuredPhotos = (input.photos || [])
    .map(normalizePhoto)
    .filter((photo): photo is PlantScanPhoto => photo !== null);
  if (structuredPhotos.length > 0) return structuredPhotos;

  const uriPhotos = photosFromUris(input.photoUris || []);
  if (uriPhotos.length > 0) return uriPhotos;

  const legacyPhotoUri = normalizePhotoUri(input.photoUri);
  return legacyPhotoUri ? [{ role: 'whole', uri: legacyPhotoUri }] : [];
}

export function getPrimaryPlantScanImageUri(input: PlantIdentificationInput): string | undefined {
  return getPlantScanPhotos(input)[0]?.uri;
}

export function getPlantScanResultImageUris(input: PlantIdentificationInput): string[] | undefined {
  const structuredPhotos = (input.photos || [])
    .map(normalizePhoto)
    .filter((photo): photo is PlantScanPhoto => photo !== null);
  if (structuredPhotos.length > 0) return structuredPhotos.map(photo => photo.uri);

  const uriPhotos = photosFromUris(input.photoUris || []);
  return uriPhotos.length > 0 ? uriPhotos.map(photo => photo.uri) : undefined;
}

export function getPreferredApproximateLocationText(
  input: PlantIdentificationInput,
): string | undefined {
  return normalizeOptionalText(input.approximateLocationText)
    || normalizeOptionalText(input.savedApproximateLocationText);
}
