export type RawMaterial = {
  id: number;
  tenant_id?: string;
  name: string;
  supplier?: string | null;
  unit_of_measure: string;
  kg_per_unit: number;
  status: string;
  notes?: string | null;
  created_at?: string;
  current_price?: {
    id?: number;
    market_value: number;
    waste_percentage: number;
    cost_per_kg: number;
    effective_date: string;
    status?: string;
    notes?: string | null;
    created_at?: string;
    loss_cost?: number;
    cost_per_unit?: number;
  } | null;
};

export type MixIngredient = {
  id: number;
  raw_material_id: number;
  raw_material_name: string;
  quantity_kg: number;
  cost_per_kg: number | null;
  line_cost: number | null;
  notes?: string | null;
};

export type Mix = {
  id: number;
  tenant_id?: string;
  client_name: string;
  name: string;
  status: string;
  version?: number;
  notes?: string | null;
  created_at?: string;
  ingredients: MixIngredient[];
  total_mix_kg: number;
  total_mix_cost: number;
  mix_cost_per_kg: number | null;
  warnings: string[];
};

export type MixIngredientInput = {
  raw_material_id: number;
  quantity_kg: number;
  notes?: string | null;
};

export type MixCreateInput = {
  client_name: string;
  name: string;
  status?: string;
  version?: number;
  notes?: string | null;
  ingredients: MixIngredientInput[];
};

export type MixUpdateInput = {
  client_name?: string;
  name?: string;
  status?: string;
  version?: number;
  notes?: string | null;
};

export type MixIngredientUpdateInput = {
  quantity_kg?: number;
  notes?: string | null;
};

export type MixCalculatorProductOption = {
  product_id: number;
  client_name: string;
  product_name: string;
  mix_id: number;
  mix_name: string;
  unit_of_measure: string;
  unit_size_kg: number;
  mix_total_kg: number;
};

export type MixCalculatorOptions = {
  clients: string[];
  products: MixCalculatorProductOption[];
};

export type MixCalculatorLine = {
  id?: number | null;
  raw_material_id?: number | null;
  raw_material_name: string;
  required_kg: number;
  mix_percentage: number;
  unit: string;
  rounding_decimals?: number;
  sort_order: number;
};

export type MixCalculatorPreview = {
  client_name: string;
  product_id: number;
  product_name: string;
  mix_id: number;
  mix_name: string;
  mix_date: string;
  batch_size_kg: number;
  total_bags: number;
  total_kg: number;
  product_unit_of_measure: string;
  product_unit_size_kg: number;
  prepared_by_name: string;
  status: string;
  notes?: string | null;
  warnings: string[];
  lines: MixCalculatorLine[];
};

export type MixCalculatorSessionSummary = {
  id: number;
  tenant_id: string;
  session_number: string;
  client_name: string;
  product_id: number;
  product_name: string;
  mix_id: number;
  mix_name: string;
  mix_date: string;
  batch_size_kg: number;
  total_bags: number;
  total_kg: number;
  product_unit_of_measure: string;
  product_unit_size_kg: number;
  prepared_by_user_id?: number | null;
  prepared_by_name: string;
  created_by: string;
  status: string;
  notes?: string | null;
  created_at: string;
  updated_at: string;
  warnings: string[];
  is_owner: boolean;
};

export type MixCalculatorSession = MixCalculatorSessionSummary & {
  lines: MixCalculatorLine[];
};

export type MixCalculatorCreateInput = {
  mix_date: string;
  client_name: string;
  product_id: number;
  batch_size_kg: number;
  prepared_by_name: string;
  status?: string;
  notes?: string | null;
};

export type MixCalculatorUpdateInput = {
  mix_date?: string;
  client_name?: string;
  product_id?: number;
  batch_size_kg?: number;
  prepared_by_name?: string;
  status?: string;
  notes?: string | null;
};

export type Product = {
  id: number;
  tenant_id?: string;
  name: string;
  client_name: string;
  mix_id?: number;
  mix_name: string;
  sale_type: string;
  own_bag?: boolean;
  visible?: boolean;
  unit_of_measure: string;
  items_per_pallet?: number;
  bagging_process?: string | null;
  distributor_margin: number | null;
  wholesale_margin: number | null;
  notes?: string | null;
  created_at?: string;
};

export type ProductCostBreakdown = {
  product_id: number;
  product_name: string;
  client_name: string;
  mix_name: string;
  cleaned_product_cost?: number;
  grading_cost?: number;
  bagging_cost?: number;
  cracking_cost?: number;
  bag_cost?: number;
  freight_cost?: number;
  finished_product_delivered: number;
  distributor_price: number | null;
  wholesale_price: number | null;
  warnings: string[];
  inputs?: Record<string, unknown>;
};

export type ProductCostingItem = {
  id: number;
  tenant_id: string;
  client_category: string;
  item_id: string | null;
  product_name: string;
  mix_product_name: string;
  unit_type: string;
  own_bag: string | null;
  unit_kg: number | null;
  items_per_pallet: number | null;
  bagging_process: string | null;
  manual_distributor_margin: number | null;
  manual_wholesale_margin: number | null;
  cleaned_product_cost_per_kg: number | null;
  grading_cost_per_kg: number | null;
  bagging_cost_per_kg: number | null;
  cracking_cost_per_kg: number | null;
  bag_cost_per_unit: number | null;
  freight_cost_per_unit: number | null;
  finished_product_delivered_cost: number | null;
  distributor_price: number | null;
  wholesale_price: number | null;
  warnings: string[];
  created_at: string;
  updated_at: string;
};

export type ProductCostingItemUpdateInput = {
  client_category?: string;
  item_id?: string | null;
  product_name?: string;
  mix_product_name?: string;
  unit_type?: string;
  own_bag?: string | null;
  unit_kg?: number | null;
  items_per_pallet?: number | null;
  bagging_process?: string | null;
  manual_distributor_margin?: number | null;
  manual_wholesale_margin?: number | null;
};

export type ProductCostingNamedInput = {
  key: string;
  label: string;
  cost: number;
};

export type ProductCostingClientInput = {
  client_category: string;
  distributor_margin: number | null;
  wholesale_margin: number | null;
};

export type ProductCostingInputs = {
  base: {
    grading_per_tonne: number;
    grading_per_kg: number;
    cracking_per_tonne: number;
    cracking_per_kg: number;
  };
  processes: ProductCostingNamedInput[];
  clients: ProductCostingClientInput[];
  bags: ProductCostingNamedInput[];
  freight: ProductCostingNamedInput[];
};

export type EditorProductRow = {
  id: number;
  tenant_id: string;
  client_name: string;
  item_id: string | null;
  name: string;
  mix_id: number;
  mix_client_name: string;
  mix_name: string;
  sale_type: string;
  unit_of_measure: string;
  visible: boolean;
  product_notes: string | null;
  mix_notes: string | null;
};

export type EditorProductUpdateInput = {
  client_name?: string;
  item_id?: string | null;
  name?: string;
  mix_id?: number;
  sale_type?: string;
  unit_of_measure?: string;
  visible?: boolean;
  notes?: string | null;
};

export type EditorMixCreateInput = {
  client_name: string;
  name: string;
  notes?: string | null;
};

export type EditorMixUpdateInput = {
  client_name?: string;
  name?: string;
  notes?: string | null;
  visible?: boolean;
};

export type EditorMixRow = {
  id: number;
  tenant_id: string;
  client_name: string;
  name: string;
  visible: boolean;
  product_count: number;
  visible_product_count: number;
  notes: string | null;
};

export type EditorMixIngredient = {
  id: number;
  raw_material_id: number;
  raw_material_name: string;
  quantity_kg: number;
  notes: string | null;
};

export type EditorMixFormula = {
  id: number;
  tenant_id: string;
  client_name: string;
  name: string;
  ingredients: EditorMixIngredient[];
  total_kg: number;
};

export type EditorResolvedMixIngredient = {
  raw_material_id: number;
  raw_material_name: string;
  quantity_kg: number;
  mix_percentage: number;
  unit: string;
  notes: string | null;
};

// A mix formula resolved exactly as the Mix Calculator reads it. `source` is
// 'product' when it comes from a representative product's own formula, or 'mix'
// when it comes from the shared mix master fallback.
export type EditorResolvedMixFormula = {
  id: number;
  tenant_id: string;
  client_name: string;
  name: string;
  source: 'product' | 'mix';
  product_id: number | null;
  ingredients: EditorResolvedMixIngredient[];
  total_kg: number;
};

export type EditorMixFormulaRowInput = {
  raw_material_id: number;
  quantity_kg: number;
  notes?: string | null;
};

export type EditorProductIngredient = {
  id: number;
  raw_material_id: number;
  raw_material_name: string;
  quantity_kg: number;
  sort_order: number;
  notes: string | null;
};

export type EditorProductFormula = {
  id: number;
  tenant_id: string;
  client_name: string;
  name: string;
  mix_id: number;
  mix_name: string;
  ingredients: EditorProductIngredient[];
  total_kg: number;
};

export type EditorIngredientRow = {
  id: number;
  name: string;
  supplier: string | null;
  unit_of_measure: string;
  kg_per_unit: number;
  status: string;
  rounding_decimals: number;
  notes: string | null;
  cost_per_kg: number | null;
  usage_count: number;
  created_at: string;
};

export type EditorIngredientCreateInput = {
  name: string;
  supplier?: string | null;
  unit_of_measure: string;
  kg_per_unit: number;
  status?: string;
  rounding_decimals?: number;
  notes?: string | null;
};

export type EditorIngredientUpdateInput = Partial<EditorIngredientCreateInput>;

export type EditorChangeFieldDelta = {
  field: string;
  label: string;
  before: string | null;
  after: string | null;
};

export type EditorChangeEvent = {
  id: number;
  entity_type: 'mix' | 'ingredient';
  entity_id: number;
  action: string;
  actor_name: string;
  actor_email: string;
  actor_role: string | null;
  summary: string;
  changes: EditorChangeFieldDelta[];
  created_at: string;
};

export type Scenario = {
  id: number;
  name: string;
  status: string;
  description?: string | null;
  overrides: Record<string, unknown>;
};

export type ClientAccessUser = {
  id: number;
  client_account_id: number;
  full_name: string;
  email: string;
  role: string;
  status: string;
  is_new_user: boolean;
  last_login_at?: string | null;
  created_at: string;
  module_permissions: ClientUserModulePermission[];
};

export type ClientUserModulePermission = {
  id: number;
  client_account_id: number;
  client_user_id: number;
  module_key: string;
  module_name: string;
  module_group: string;
  description?: string | null;
  access_level: string;
  updated_at: string;
  created_at: string;
};

export type ClientAccessFeature = {
  id: number;
  client_account_id: number;
  feature_key: string;
  feature_name: string;
  feature_group: string;
  description?: string | null;
  enabled: boolean;
  updated_at: string;
  created_at: string;
};

export type ClientAccessAccount = {
  id: number;
  tenant_id: string;
  name: string;
  client_code: string;
  status: string;
  powerbi_workspace?: string | null;
  notes?: string | null;
  created_at: string;
  users: ClientAccessUser[];
  features: ClientAccessFeature[];
  active_user_count: number;
  new_user_count: number;
  enabled_feature_count: number;
  total_feature_count: number;
  audit_history: ClientAccessAuditEvent[];
};

export type ClientAccessAuditEvent = {
  id: number;
  client_account_id: number;
  actor_type: string;
  actor_name: string;
  actor_email: string;
  actor_role: string;
  action: string;
  target_type: string;
  target_id?: number | null;
  module_key?: string | null;
  summary: string;
  created_at: string;
};

export type ClientAccessExportRow = Record<string, unknown>;

export type ClientAccessPowerBiExport = {
  generated_at: string;
  client_rows: ClientAccessExportRow[];
  user_rows: ClientAccessExportRow[];
  feature_rows: ClientAccessExportRow[];
  permission_rows: ClientAccessExportRow[];
  audit_rows: ClientAccessExportRow[];
  clients: ClientAccessAccount[];
};

export type DashboardSummary = {
  raw_materials: {
    count: number;
    total_market_value: number;
    latest: { id: number; name: string; market_value: number; cost_per_kg: number; effective_date: string | null } | null;
  } | null;
  mixes: {
    count: number;
    average_cost_per_kg: number;
    top: {
      id: number;
      name: string;
      client_name: string;
      ingredients_count: number;
      total_mix_kg: number;
      total_mix_cost: number;
      mix_cost_per_kg: number | null;
      warnings: string[];
    } | null;
  } | null;
  products: {
    count: number;
    top: { id: number; product_name: string; client_name: string; finished_product_delivered: number; warnings: string[] } | null;
    top_products: Array<{ id: number; product_name: string; client_name: string; finished_product_delivered: number; warnings: string[] }>;
  } | null;
  trend_seeds: {
    raw_material_cost_per_kg: number[];
    mix_cost_per_kg: number[];
    product_finished_delivered: number[];
  };
  operations?: {
    period_label: string;
    total_kg: number;
    total_bags: number;
    entry_count: number;
    estimated_wholesale_value: number;
    priced_entry_count: number;
    top_products: Array<{
      product_name: string;
      client_name: string | null;
      kg: number;
      bags: number;
      entries: number;
    }>;
    client_totals: Array<{
      client_name: string;
      kg: number;
    }>;
    pricing_issues: {
      missing_lookup: number;
      missing_unit_kg: number;
      missing_pallet_qty: number;
      missing_price: number;
      invalid_margin: number;
      total: number;
    };
    produced_not_priced: Array<{
      product_name: string;
      kg: number;
      status: string;
      warnings: string[];
    }>;
  } | null;
};

export type LoginResponse = {
  name: string;
  email: string;
  role: string;
  token?: string | null;
  tenant_id?: string | null;
  client_role?: string | null;
  user_id?: number | null;
  client_account_id?: number | null;
  module_permissions?: Record<string, string>;
  // Permission-key array populated by the internal Hunter Stock Feeds login.
  // Drives permission-based UI gating; legacy client logins leave it undefined.
  permissions?: string[];
  // Display-friendly role label (e.g. "Admin", "Operations") when role === 'internal'.
  role_name?: string | null;
};

// Internal Hunter Stock Feeds user (the access-control system), as returned by
// /api/access/users. Distinct from the B2B ordering ClientUser accounts.
export type InternalUser = {
  id: number;
  email: string;
  name: string;
  is_active: boolean;
  role: string | null;
  role_id: number | null;
  // Lean owner accounts: editable but never deletable.
  is_protected: boolean;
};

export type InternalRoleOption = {
  id: number;
  name: string;
  description: string | null;
};

export type InternalRoleModuleDefinition = {
  key: string;
  label: string;
  description: string;
  levels: string[];
};

export type InternalRole = {
  id: number;
  name: string;
  description: string | null;
  permissions: string[];
  module_permissions: Record<string, string>;
  is_protected: boolean;
  user_count: number;
};

export type InternalRoleCreateInput = {
  name: string;
  description?: string | null;
  module_permissions: Record<string, string>;
};

export type InternalRoleUpdateInput = {
  name?: string;
  description?: string | null;
  module_permissions?: Record<string, string>;
};

export type InternalUserCreateInput = {
  email: string;
  name: string;
  role_id?: number | null;
  is_active?: boolean;
  password?: string | null;
};

export type InternalUserUpdateInput = {
  name?: string;
  email?: string;
  role_id?: number | null;
  is_active?: boolean;
};

export type RawMaterialCreateInput = {
  name: string;
  supplier?: string | null;
  unit_of_measure: string;
  kg_per_unit: number;
  status?: string;
  notes?: string | null;
  initial_price: {
    market_value: number;
    waste_percentage: number;
    effective_date: string;
    status?: string;
    notes?: string | null;
  };
};

export type RawMaterialPriceCreateInput = {
  market_value: number;
  waste_percentage: number;
  effective_date: string;
  status?: string;
  notes?: string | null;
};

export type ClientUserCreateInput = {
  client_account_id: number;
  full_name: string;
  email: string;
  role?: string;
  status?: string;
  is_new_user?: boolean;
};

export type ClientUserUpdateInput = {
  full_name?: string;
  email?: string;
  role?: string;
  status?: string;
  is_new_user?: boolean;
};

export type ThroughputProduct = {
  id: number;
  tenant_id: string;
  item_id: string | null;
  name: string;
  client_name: string | null;
  default_bag_size: number | null;
  is_bulka_default: boolean;
  active: boolean;
  is_stock_item: boolean;
  notes: string | null;
  created_at: string;
  updated_at: string;
};

export type ThroughputQuantityType = 'bags' | 'kg';

export type ThroughputEntry = {
  id: number;
  tenant_id: string;
  production_date: string;
  product_id: number | null;
  product_name_snapshot: string;
  bag_size: number | null;
  scales_checked: boolean;
  label_correct: boolean;
  bag_sealed: boolean;
  pallet_good_condition: boolean;
  for_order: boolean;
  for_stock: boolean;
  job_number: string | null;
  stock_quantity: number | null;
  sample_box_no: string | null;
  test_weight_1: number | null;
  test_weight_2: number | null;
  test_weight_3: number | null;
  test_weight_4: number | null;
  test_weight_5: number | null;
  quantity: number;
  quantity_type: ThroughputQuantityType;
  calculated_kg: number;
  staff_name: string | null;
  notes: string | null;
  qa_passed: boolean;
  created_by: string | null;
  created_at: string;
  updated_at: string;
};

export type ThroughputEntryCreateInput = {
  production_date: string;
  product_id?: number | null;
  product_name_snapshot?: string;
  bag_size?: number | null;
  scales_checked?: boolean;
  label_correct?: boolean;
  bag_sealed?: boolean;
  pallet_good_condition?: boolean;
  for_order?: boolean;
  for_stock?: boolean;
  job_number?: string | null;
  stock_quantity?: number | null;
  sample_box_no?: string | null;
  test_weight_1?: number | null;
  test_weight_2?: number | null;
  test_weight_3?: number | null;
  test_weight_4?: number | null;
  test_weight_5?: number | null;
  quantity: number;
  quantity_type: ThroughputQuantityType;
  staff_name?: string | null;
  notes?: string | null;
};

export type ThroughputEntryUpdateInput = Partial<ThroughputEntryCreateInput>;

export type ThroughputImportResult = {
  entries_imported: number;
  entries_skipped: number;
  products_created: number;
  errors: string[];
};

export type ThroughputDeleteAllResult = {
  entries_deleted: number;
};

export type ThroughputEntryListParams = {
  date_from?: string;
  date_to?: string;
  product_id?: number | null;
  staff_name?: string;
  quantity_type?: ThroughputQuantityType;
  limit?: number;
};

export type ThroughputProductCreateInput = {
  item_id?: string | null;
  name: string;
  client_name?: string | null;
  default_bag_size?: number | null;
  is_bulka_default?: boolean;
  active?: boolean;
  is_stock_item?: boolean;
  notes?: string | null;
};

export type ThroughputProductUpdateInput = Partial<ThroughputProductCreateInput>;

// --- B2B ordering portal ----------------------------------------------------

export type OrderingPriceInfo = {
  unit_price: number | null;
  price_source: 'fixed' | 'contract' | 'price_list' | 'tiered' | 'base' | 'quote';
  price_rule_id: number | null;
  discount_percent: number;
  requires_quote: boolean;
  label: string;
};

export type CatalogueProduct = {
  id: number;
  name: string;
  sku: string;
  description?: string | null;
  category: string;
  image_url?: string | null;
  unit_size?: string | null;
  unit_of_measure: string;
  min_order_quantity: number;
  stock_status: string;
  active: boolean;
  requires_quote: boolean;
  base_price?: number | null;
  created_at?: string;
  price?: OrderingPriceInfo;
};

export type OrderLine = {
  id: number;
  product_id: number;
  product_name: string;
  product_sku: string;
  quantity: number;
  unit_price: number | null;
  line_total: number | null;
  requires_quote: boolean;
  price_source: string;
  discount_percent: number;
  notes?: string | null;
  // admin-only
  resolved_unit_price?: number | null;
  admin_override_price?: number | null;
  admin_override_reason?: string | null;
  price_rule_id?: number | null;
};

export type OrderStatusHistoryEntry = {
  id: number;
  from_status: string | null;
  to_status: string;
  actor_type: string;
  actor_name?: string | null;
  note?: string | null;
  created_at: string;
};

export type Order = {
  id: number;
  order_number: string | null;
  status: string;
  client_account_id: number;
  created_by_name?: string | null;
  purchase_order_number?: string | null;
  delivery_notes?: string | null;
  requested_delivery_date?: string | null;
  fulfilment_method: string;
  subtotal_ex_gst: number;
  requires_quote: boolean;
  submitted_at?: string | null;
  created_at: string;
  updated_at: string;
  editable: boolean;
  lines: OrderLine[];
  // admin-only
  raw_status?: string;
  admin_notes?: string | null;
  reopened?: boolean;
  xero_status?: string;
  xero_invoice_id?: string | null;
  customer_name?: string | null;
  status_history?: OrderStatusHistoryEntry[];
  notifications?: { channel: string; recipients: string[]; delivered: boolean; detail: string }[];
  xero_result?: { status: string; stubbed: boolean; message: string; xero_invoice_id: string | null };
};

export type OrderLineInput = { product_id: number; quantity: number; notes?: string | null };

export type DraftOrderInput = {
  lines: OrderLineInput[];
  purchase_order_number?: string | null;
  delivery_notes?: string | null;
  requested_delivery_date?: string | null;
  fulfilment_method?: string;
};

export type OrderingCustomer = {
  id: number;
  name: string;
  client_code: string;
  tenant_id: string;
  status: string;
  notes?: string | null;
  user_count: number;
  price_list_id: number | null;
  discount_percent: number;
  xero_contact_id?: string | null;
  xero_contact_name?: string | null;
  created_at: string;
};

export type OrderingCustomerUser = {
  id: number;
  client_account_id: number;
  full_name: string;
  email: string;
  role: string;
  status: string;
  created_at: string;
};

export type PriceTierInput = { min_quantity: number; unit_price: number };

export type CustomerPricing = {
  customer_id: number;
  price_list_id: number | null;
  discount_percent: number;
  product_prices: {
    id: number;
    product_id: number;
    unit_price: number | null;
    rule_type: string;
    contract_reference?: string | null;
    notes?: string | null;
    active: boolean;
    tiers: { id: number; min_quantity: number; unit_price: number }[];
  }[];
};

export type CustomerVisibilityRow = {
  product_id: number;
  name: string;
  sku: string;
  category: string;
  visible: boolean;
};

export type OrderingNotificationSettings = {
  internal_recipients: string | null;
  send_customer_confirmation: boolean;
  require_po_number: boolean;
  from_email: string | null;
};

export type XeroStatus = {
  connection: { configured: boolean; mode: string; base_url: string; checked_at: string; missing_env: string[] };
  contact_links: { linked: number; total: number; unlinked: number };
  recent_syncs: {
    id: number;
    order_id: number;
    status: string;
    xero_invoice_id: string | null;
    response_message: string | null;
    created_at: string;
  }[];
};

export type XeroContact = {
  contact_id: string;
  name: string;
  email: string | null;
  status: string;
};

export type XeroContactList = {
  contacts: XeroContact[];
  stubbed: boolean;
};

export type XeroContactLinkRow = {
  customer_id: number;
  customer_name: string;
  client_code: string;
  linked: boolean;
  xero_contact_id: string | null;
  xero_contact_name: string | null;
  xero_contact_email: string | null;
  last_synced_at: string | null;
  suggested_contact_id: string | null;
};
