import {
  getKpis,
  getMonthlyOrders,
  getMonthlyProduction,
  getDispatchAnalysis,
  getRecentOrders,
  getStageBreakdown,
  getIdleCandidates,
  getClientNames,
  getWireSizesByProduct,
} from '../repositories/dashboard.repo.js';
import { findAll as findAllOrders } from '../repositories/order.repo.js';
import { withIdleMinutes } from './order.service.js';
import { findAll as findAllStages } from '../repositories/stage.repo.js';
import { officeMinutesElapsed } from './officeCalendar.service.js';
import type { Kpi, RecentOrderRow, Order, Stage, StageBreakdownRow, StageIdleSummaryRow } from '../types/index.js';

// Narrows getIdleCandidates()'s wall-clock pre-filtered rows down to the
// ones that are actually idle by office-hours-aware minutes (see
// officeCalendar.service.ts's officeMinutesElapsed for why this differs
// from a raw NOW() - entered_at diff).
async function getTrulyIdleCandidates() {
  const candidates = await getIdleCandidates();
  const now = new Date();
  return candidates.filter((c) => officeMinutesElapsed(c.enteredAt, now) > c.thresholdMinutes);
}

export async function kpi(): Promise<Kpi[]> {
  const [kpis, idle] = await Promise.all([getKpis(), getTrulyIdleCandidates()]);
  return [...kpis, { id: 'stage-idle', label: 'Stage Idle', value: idle.length, delta: 0, trend: 'down' }];
}

export async function stageBreakdown(): Promise<StageBreakdownRow[]> {
  return getStageBreakdown();
}

// Bare stage list (id/name/color/sortOrder/idleThresholdMinutes) gated only
// by DASHBOARD_VIEW — lets a dashboard-only login (e.g. one restricted to
// just the Stage-wise Pending/Stage Idle cards, with no STAGES_VIEW/
// ORDERS_VIEW/ORDERS_EDIT/ORDERS_STAGE_UPDATE) resolve stage names on the
// Orders page drill-down instead of getting an empty list back from
// GET /api/stages and having every stage silently misresolve to "Not
// Started" — same reasoning as clientNames()/wireSizesByProduct() above.
export async function stageNames(): Promise<Stage[]> {
  return findAllStages();
}

export async function clientNames(): Promise<{ id: string; name: string }[]> {
  return getClientNames();
}

export async function wireSizesByProduct(): Promise<{ productId: string; wireSizeName: string }[]> {
  return getWireSizesByProduct();
}

export async function stageIdleSummary(): Promise<StageIdleSummaryRow[]> {
  const [idle, stages] = await Promise.all([getTrulyIdleCandidates(), findAllStages()]);
  const countByStage = new Map<string, number>();
  for (const c of idle) countByStage.set(c.stageId, (countByStage.get(c.stageId) ?? 0) + 1);

  // Every stage is listed, including ones with nothing idle right now — the
  // picker should read as a complete stage list, same as
  // getStageBreakdown()'s "Not Started" bucket always appearing.
  return stages.map((s) => ({ stageId: s.id, name: s.name, color: s.color, count: countByStage.get(s.id) ?? 0 }));
}

export async function monthlyOrders(): Promise<{ month: string; current_year: number; previous_year: number }[]> {
  return getMonthlyOrders();
}

export async function monthlyProduction(): Promise<{ month: string; target: number; achieved: number }[]> {
  return getMonthlyProduction();
}

const WEEKDAYS_SHORT = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'];

export async function dispatchAnalysis(): Promise<{ day: string; dispatched: number; pending: number; delayed: number }[]> {
  const rows = await getDispatchAnalysis();
  const byDate = new Map(rows.map((r) => [r.date, r]));

  const result: { day: string; dispatched: number; pending: number; delayed: number }[] = [];
  for (let i = 6; i >= 0; i--) {
    const d = new Date();
    d.setDate(d.getDate() - i);
    const iso = d.toISOString().slice(0, 10);
    const row = byDate.get(iso);
    result.push({
      day: WEEKDAYS_SHORT[(d.getDay() + 6) % 7]!,
      dispatched: Number(row?.dispatched ?? 0),
      pending: Number(row?.pending ?? 0),
      delayed: Number(row?.delayed ?? 0),
    });
  }
  return result;
}

export async function recentOrders(): Promise<RecentOrderRow[]> {
  return getRecentOrders();
}

// Dashboard-scoped order feed for the activity/summary/customer tables —
// gated only by DASHBOARD_VIEW (see dashboard.routes.ts), so a user with
// just that permission still sees full dashboard data without also needing
// ORDERS_VIEW/CLIENTS_VIEW/EMPLOYEES_VIEW. Names come pre-joined from
// order.repo.ts, and idle minutes are attached the same way order.service.ts's
// list()/get() do, so the Stage Idle modal's printed report also works here.
export async function ordersOverview(): Promise<Order[]> {
  // High enough that the dashboard's date-filterable summary modals
  // (Order Summary, Dispatch Summary) can reach any past date, not just
  // whatever fits in a small recent-orders window.
  const { rows } = await findAllOrders({ limit: 5000, sortBy: 'order_date', sortOrder: 'desc' });
  return rows.map(withIdleMinutes);
}
