// Turns what was typed in a form (text) into the typed values the store validates, and gives the SAME error messages on
// the page, at once, without waiting for the server. The server still checks everything again.
import { parseDecimal, parseMoneyToCents, validateMaterial, validateSettings, type Errors, type MaterialDraft, type SettingsDraft } from "./validation";
import type { PriceRounding } from "./cost";

const orNaN = (value: number | null): number => (value === null ? Number.NaN : value);

export interface MaterialText {
  name: string;
  unit: string;
  price: string;
  quantity: string;
  waste: string;
}

export function materialFromText(text: MaterialText): { draft: MaterialDraft; errors: Errors } {
  const draft: MaterialDraft = {
    name: text.name,
    unit: text.unit,
    packPriceCents: orNaN(parseMoneyToCents(text.price)),
    packQuantity: orNaN(parseDecimal(text.quantity)),
    // An empty waste means none.
    wastePercent: text.waste.trim() === "" ? 0 : orNaN(parseDecimal(text.waste)),
  };
  const result = validateMaterial(draft);
  return { draft, errors: result.ok ? {} : result.errors };
}

export interface SettingsText {
  hourly: string;
  margin: string;
  rounding: string;
  deleteData?: boolean;
}

export function settingsFromText(text: SettingsText): { draft: SettingsDraft; errors: Errors } {
  const draft: SettingsDraft = {
    // An empty hourly rate means "do not count my time".
    hourlyRateCents: text.hourly.trim() === "" ? 0 : orNaN(parseMoneyToCents(text.hourly)),
    targetMarginPercent: orNaN(parseDecimal(text.margin)),
    priceRounding: text.rounding as PriceRounding,
    deleteDataOnUninstall: text.deleteData ?? false,
  };
  const result = validateSettings(draft);
  return { draft, errors: result.ok ? {} : result.errors };
}

// The messages of a set of errors, in one list (for a summary banner).
export function messagesOf(errors: Errors): string[] {
  return Object.entries(errors)
    .filter(([field]) => field !== "form")
    .map(([, message]) => message);
}
