// ── Auth ──
export interface AuthUser {
  id: string;
  name: string;
  email: string;
  role: string;
  permissions: string[];
  // Restricts which stage-to-stage moves this employee may perform (see
  // order.service.ts's advanceStage) — empty means unrestricted. Sent to the
  // frontend so OrderProductRow can pre-filter the stage dropdown instead of
  // only finding out a move is disallowed after the API rejects it.
  stageTransitions: { fromStageId: string; toStageId: string }[];
  // A single stage cutoff for the Pending Deliveries dashboard card only —
  // unrelated to stageTransitions. Null means unrestricted (sees every
  // pending delivery, today's behavior). See dashboard.service.ts.
  pendingDeliveryStageId: string | null;
}

export interface LoginPayload {
  identifier: string;
  password: string;
  rememberMe: boolean;
}

export interface LoginResult {
  user: AuthUser;
  token: string;
}

// ── Client ──
export interface Seal {
  id: string;
  client_id: string;
  name: string;
}

export interface Client {
  id: string;
  name: string;
  mobile: string;
  alternate_mobile?: string;
  email?: string;
  send_sms: boolean;
  seals?: Seal[];
}

// ── Product Category ──
export interface ProductCategory {
  id: string;
  name: string;
}

// ── Product master lists (Metal Type / Purity / Size / Weight) ──
export interface MetalType {
  id: string;
  name: string;
}

export interface Purity {
  id: string;
  name: string;
}

// ── Hallmark Grade (e.g. HM, HUID) — separate from Purity/Karat, chosen per
// order line rather than as part of the product/variant itself ──
export interface HallmarkGrade {
  id: string;
  name: string;
}

export interface Size {
  id: string;
  name: string;
}

export interface Weight {
  id: string;
  name: string;
}

// ── Item / Item Group / Wire Size / Hook / Endcap ──
export interface Item {
  id: string;
  name: string;
}

export interface WireSize {
  id: string;
  name: string;
}

export interface Hook {
  id: string;
  name: string;
}

export interface Endcap {
  id: string;
  name: string;
}

// ── Office Calendar (office hours + holiday/half-day calendar used to
// convert wall-clock idle time into office-minutes idle time) ──
export interface OfficeSettings {
  startTime: string; // 'HH:MM:SS'
  endTime: string; // 'HH:MM:SS'
  weeklyOffDay: number; // 0 = Sunday .. 6 = Saturday
}

// A calendar-day override. 'holiday'/'half_day' turn an otherwise-open day
// off (or shorten it); 'active_day' does the reverse — forces a normally
// closed day (the weekly off day) to run full/normal office hours, for the
// one-off case where staff actually worked that day.
export interface HolidayEntry {
  id: string;
  date: string; // 'YYYY-MM-DD'
  type: 'holiday' | 'half_day' | 'active_day';
  halfDayStart?: string; // 'HH:MM:SS', only for type 'half_day'
  halfDayEnd?: string;
  remark?: string;
}

// ── Stage (production workflow master, drives order_products.completed_stages) ──
export interface Stage {
  id: string;
  name: string;
  color: string;
  sort_order: number;
  idle_threshold_minutes: number;
}

// ── Product (Variant) ──
// `name` holds the auto-generated variant name (Item-Category-Purity-ChainSize-
// Weight-WireSize) for rows created after the Item/Variant split — see
// buildVariantName() in utils/variantName.ts and product.service.ts.
export interface Product {
  id: string;
  name: string;
  item_id?: string;
  metal_type_id?: string;
  purity_id?: string;
  category_id?: string;
  size_id?: string;
  weight_id?: string;
  wire_size_id?: string;
  hook_id?: string;
  endcap_id?: string;
  huid?: string;
}

// ── Employee ──
export interface Employee {
  id: string;
  code: string;
  name: string;
  mobile: string;
  email?: string;
  role_id: string;
  auth_enabled: boolean;
  user_id?: string;
  permission_overrides?: { permission: string; effect: 'grant' | 'deny' }[];
  // Restricts which stage-to-stage moves this employee may perform on the
  // Orders page (see order.service.ts's advanceStage) — empty/absent means
  // unrestricted (today's behavior), matching how permission_overrides only
  // narrows access when rows actually exist.
  stage_transitions?: { fromStageId: string; toStageId: string }[];
  // A single stage cutoff for the Pending Deliveries dashboard card only —
  // unrelated to stage_transitions (that's about which moves an employee
  // can *perform*; this is about what they can *see* on that one card).
  // Null/absent means unrestricted. See dashboard.service.ts.
  pending_delivery_stage_id?: string | null;
}

// ── Role ──
export interface Role {
  id: string;
  name: string;
  is_system: boolean;
  permissions: string[] | '*';
}

// ── Order ──
export type ReceivedThrough = 'Phone' | 'WhatsApp' | 'Email' | 'Direct Visit';
export type OrderPriority = 'Normal' | 'Urgent';
export type OrderLifecycle = 'active' | 'cancelled';
export type OrderStatus = 'Pending' | 'Completed' | 'Cancelled';

export interface OrderProduct {
  id: string;
  order_id: string;
  product_id: string;
  quantity: number;
  weight: number;
  size?: string;
  jo_no?: string;
  jo_no_entered_at?: string;
  remark?: string;
  // Hallmark grade (HM, HUID, ...) picked per order line, independent of the
  // product's own purity — see hallmarkGrade.repo.ts.
  hallmark_grade_id?: string;
  completed_stages: number;
  stage_updated_at?: string;
  // When the line entered its *current* stage — the entered_at of its still-open
  // order_stage_history row (see orderStageHistory.repo.ts's getCurrentStage).
  // Undefined for a line that's never advanced past "Not Started". Combined
  // with the stage's own idle_threshold_minutes, this is what lets the
  // frontend compute "Stage Idle" client-side the same way it already
  // computes JO/stage-pending, without a separate idle-items endpoint.
  stage_entered_at?: string;
  // Office-hours-aware idle minutes for the current stage — computed from
  // stage_entered_at by officeCalendar.service.ts's officeMinutesElapsed()
  // at the service layer (order.service.ts), not stored. Excludes closed
  // hours, the weekly off day, and holiday_calendar entries, so it's the
  // number to compare against the stage's idle_threshold_minutes — never
  // recompute idle time as a raw Date.now() diff on the frontend.
  stage_idle_minutes?: number;
  dispatched: boolean;
  dispatched_quantity?: number;
  dispatched_weight?: number;
  dispatch_date?: string;
  dispatched_by_employee_id?: string;
  // Free-text alternative to dispatched_by_employee_id, for a dispatch made
  // by someone who isn't a registered employee — set instead of, never
  // alongside, the employee id.
  dispatched_by_name?: string;
  // Who received the dispatch on the other side — always manual free-text,
  // there's no registered-contact equivalent to an employee id here.
  received_by_name?: string;
  cancelled: boolean;
  cancelled_quantity?: number;
  cancelled_weight?: number;
  cancel_date?: string;
  cancelled_by_employee_id?: string;
  cancel_reason?: string;
  created_at?: string;
  updated_at?: string;
  // Set to the most recent order_returns row that touched this line (see
  // orderReturn.service.ts's approve(), which applies a return in place
  // rather than creating a new line) — NULL for a line that's never been
  // returned. Lets order.service.ts's dispatch functions know to also
  // progress the linked order_returns row when this line becomes fully
  // (re-)dispatched, and lets the frontend show a "Returned" badge.
  return_id?: string;
  // Joined from order_returns via return_id — current status of the most
  // recent return on this line, so the frontend badge reflects real state
  // ("Return Pending" / "Returned" while active / a lighter tag once the
  // redelivery completes) instead of a flat permanent tag.
  return_status?: OrderReturnStatus;
  // Read-only display labels joined in for callers whose own permission set
  // doesn't include PRODUCTS_VIEW/EMPLOYEES_VIEW — see order.repo.ts joins.
  product_name?: string;
  category_name?: string;
  hallmark_grade_name?: string;
  dispatched_by_employee_name?: string;
  cancelled_by_employee_name?: string;
  // No `_id` counterpart to join a display name from — received_by_name
  // above is already the display value.
}

export interface Order {
  id: string;
  order_no: string;
  order_date: string;
  client_id: string;
  taken_by_employee_id: string;
  received_through: ReceivedThrough;
  delivery_date: string;
  priority: OrderPriority;
  received_by_client_contact?: string;
  so_number?: string;
  so_number_entered_at?: string;
  po_number?: string;
  po_date?: string;
  seal_id?: string;
  remarks?: string;
  products: OrderProduct[];
  lifecycle: OrderLifecycle;
  created_at?: string;
  // Read-only display labels joined in so ORDERS_VIEW alone is enough to
  // render full order details, without also needing CLIENTS_VIEW/EMPLOYEES_VIEW.
  client_name?: string;
  taken_by_employee_name?: string;
  // Approval workflow — orders created directly by an orders.approve holder
  // are 'approved' immediately (approved_by = themselves); orders that went
  // through order_approval_requests carry both fields.
  approval_status?: 'pending' | 'approved';
  requested_by_employee_id?: string;
  requested_by_employee_name?: string;
  approved_by_employee_id?: string;
  approved_by_employee_name?: string;
  approved_at?: string;
}

// ── Order Stage History ──
export interface OrderStageHistory {
  id: string;
  order_product_id: string;
  stage_id: string;
  entered_at: string;
  completed_at?: string;
  employee_id?: string;
  remarks?: string;
}

// ── Order Comment ──
export interface OrderComment {
  id: string;
  order_id: string;
  employee_id: string;
  comment: string;
  created_at: string;
}

// ── Order Return ──
// No separate 'approved' state, since approval immediately flips straight
// to 'active' (that's the moment the original line's dispatched counters
// are rolled back and it re-enters the chosen stage) — see
// orderReturn.service.ts's approve(). 'reverted' is the undo of that: an
// approver can revert an 'active' return (not yet fully redelivered) back
// to a normal delivered line — see revert() in the same file.
export type OrderReturnStatus = 'pending' | 'rejected' | 'active' | 'completed' | 'reverted';

export interface OrderReturn {
  id: string;
  order_id: string;
  // The *original* delivered line this return was raised against.
  order_product_id: string;
  returned_quantity: number;
  // Total weight (matches order_dispatch_history.weight's convention), not
  // per-unit — divided by returned_quantity to get the new line's per-unit
  // weight on approval.
  returned_weight: number;
  reason: string;
  target_stage_id: string;
  status: OrderReturnStatus;
  requested_by_employee_id: string;
  requested_at?: string;
  approved_by_employee_id?: string;
  approved_at?: string;
  rejected_by_employee_id?: string;
  rejected_at?: string;
  rejection_reason?: string;
  returned_date: string;
  next_delivery_date?: string;
  created_at?: string;
  updated_at?: string;
  // Read-only display labels joined in, same convention as Order/OrderProduct.
  order_no?: string;
  jo_no?: string;
  so_number?: string;
  client_name?: string;
  product_name?: string;
  target_stage_name?: string;
  requested_by_employee_name?: string;
  approved_by_employee_name?: string;
  rejected_by_employee_name?: string;
}

// ── Notification ──
export interface Notification {
  id: string;
  user_id: string;
  order_id?: string;
  type: string;
  title: string;
  message?: string;
  is_read: boolean;
  read_at?: string;
  created_at: string;
}

// ── Activity Log ──
export interface ActivityLog {
  id: string;
  user_id?: string;
  entity_type: string;
  entity_id?: string;
  action: string;
  old_values?: unknown;
  new_values?: unknown;
  description?: string;
  ip_address?: string;
  created_at: string;
}

// ── Dashboard ──
export interface Kpi {
  id: string;
  label: string;
  value: number;
  delta: number;
  trend: 'up' | 'down';
  focus?: string;
  orderStatus?: string;
}

export interface StageBreakdownRow {
  stageId: string;
  name: string;
  color: string;
  count: number;
}

export interface StageIdleSummaryRow {
  stageId: string;
  name: string;
  color: string;
  count: number;
}

export interface RecentOrderRow {
  order_number: string;
  customer: string;
  date: string;
  amount: number;
  status: string;
  employee: string;
}

// ── Report ──
export interface ReportColumn {
  key: string;
  header: string;
  align?: 'left' | 'right';
}

export type ReportCell = string | number;

export interface ReportSummaryField {
  label: string;
  value: string;
}

export interface ReportResult {
  columns: ReportColumn[];
  rows: Record<string, ReportCell>[];
  totals: Record<string, ReportCell>;
  summary?: ReportSummaryField[];
}

// ── Pagination ──
export interface PaginatedResult<T> {
  data: T[];
  total: number;
  page: number;
  limit: number;
}
