/**
 * ChronoMind backend client — typed HTTP wrappers for the chronomind-backend (port 4011).
 *
 * Auth: Bearer token from the caller's JWT (same JWT_SECRET as platform-service).
 */

import { config } from './config.js';

export interface ChronoMindClientOptions {
  token?: string;
  requestId?: string;
}

async function chronomindFetch<T>(
  path: string,
  init: RequestInit,
  opts: ChronoMindClientOptions
): Promise<T> {
  const headers: Record<string, string> = {
    'Content-Type': 'application/json',
    ...(opts.token ? { Authorization: `Bearer ${opts.token}` } : {}),
    ...(opts.requestId ? { 'x-request-id': opts.requestId } : {}),
  };
  const res = await fetch(`${config.CHRONOMIND_BACKEND_URL}/api${path}`, {
    ...init,
    headers: { ...((init.headers as Record<string, string>) ?? {}), ...headers },
    signal: AbortSignal.timeout(15_000),
  });
  if (!res.ok) {
    const body = await res.text().catch(() => '');
    throw new Error(`chronomind-backend ${init.method ?? 'GET'} ${path} → ${res.status}: ${body}`);
  }
  return res.json() as Promise<T>;
}

// ── Timers ─────────────────────────────────────────────────────────────────

export interface TimerDoc {
  id: string;
  userId: string;
  productId: string;
  label: string;
  description?: string;
  type: 'countdown' | 'alarm' | 'pomodoro';
  state: 'active' | 'paused' | 'fired' | 'snoozed' | 'dismissed' | 'completed' | 'warning';
  urgency: 'critical' | 'important' | 'standard' | 'gentle' | 'passive';
  duration?: number;
  targetTime?: string;
  category?: string;
  createdAt: string;
  lastSyncedAt: string;
  syncVersion: number;
}

export interface TimerCreateInput {
  id: string;
  label: string;
  type: 'countdown' | 'alarm' | 'pomodoro';
  state: 'active' | 'paused';
  urgency: 'critical' | 'important' | 'standard' | 'gentle' | 'passive';
  duration?: number;
  targetTime?: string;
  category?: string;
  cascade?: unknown;
  syncVersion: number;
  deviceId?: string;
}

export function chronomindTimerCreate(
  input: TimerCreateInput,
  opts: ChronoMindClientOptions
): Promise<TimerDoc> {
  return chronomindFetch('/timers', { method: 'POST', body: JSON.stringify(input) }, opts);
}

export function chronomindTimersList(
  params: { limit?: number; offset?: number; type?: string; state?: string },
  opts: ChronoMindClientOptions
): Promise<{ items: TimerDoc[]; total: number }> {
  const qs = new URLSearchParams();
  if (params.limit !== undefined) qs.set('limit', String(params.limit));
  if (params.offset !== undefined) qs.set('offset', String(params.offset));
  if (params.type) qs.set('type', params.type);
  if (params.state) qs.set('state', params.state);
  const q = qs.toString();
  return chronomindFetch(`/timers${q ? `?${q}` : ''}`, { method: 'GET' }, opts);
}

export function chronomindSyncStatus(opts: ChronoMindClientOptions): Promise<{
  userId: string;
  productId: string;
  totalTimers: number;
  active: number;
  pending: number;
  unsyncedCount: number;
  lastSyncedAt: string | null;
  generatedAt: string;
}> {
  return chronomindFetch('/timers/sync-status', { method: 'GET' }, opts);
}

// ── Routines ───────────────────────────────────────────────────────────────

export interface RoutineDoc {
  id: string;
  userId: string;
  productId: string;
  name: string;
  description?: string;
  steps: unknown[];
  totalDurationMinutes: number;
  status: 'template' | 'ready' | 'active' | 'paused' | 'completed' | 'cancelled';
  isTemplate: boolean;
  category?: string;
  createdAt: string;
  lastSyncedAt: string;
  syncVersion: number;
}

export function chronomindRoutineGet(
  routineId: string,
  opts: ChronoMindClientOptions
): Promise<RoutineDoc> {
  return chronomindFetch(`/routines/${routineId}`, { method: 'GET' }, opts);
}

export function chronomindRoutinesList(
  params: { limit?: number; offset?: number; isTemplate?: boolean },
  opts: ChronoMindClientOptions
): Promise<{ items: RoutineDoc[]; total: number }> {
  const qs = new URLSearchParams();
  if (params.limit !== undefined) qs.set('limit', String(params.limit));
  if (params.offset !== undefined) qs.set('offset', String(params.offset));
  if (params.isTemplate !== undefined) qs.set('isTemplate', String(params.isTemplate));
  const q = qs.toString();
  return chronomindFetch(`/routines${q ? `?${q}` : ''}`, { method: 'GET' }, opts);
}

// ── Households ────────────────────────────────────────────────────────────

export function chronomindHouseholdsList(
  params: { limit?: number; offset?: number },
  opts: ChronoMindClientOptions
): Promise<{ items: unknown[]; total: number }> {
  const qs = new URLSearchParams();
  if (params.limit !== undefined) qs.set('limit', String(params.limit));
  if (params.offset !== undefined) qs.set('offset', String(params.offset));
  const q = qs.toString();
  return chronomindFetch(`/households${q ? `?${q}` : ''}`, { method: 'GET' }, opts);
}

export function chronomindSharedTimerShare(
  timerId: string,
  targets: { userId?: string; householdId?: string }[],
  opts: ChronoMindClientOptions
): Promise<{ sharedTimerId: string; timerId: string; targetCount: number; sharedAt: string }> {
  return chronomindFetch(
    '/shared-timers',
    { method: 'POST', body: JSON.stringify({ timerId, targets }) },
    opts
  );
}

export function chronomindTimerDelete(
  timerId: string,
  opts: ChronoMindClientOptions
): Promise<{ success: boolean }> {
  return chronomindFetch(`/timers/${timerId}`, { method: 'DELETE' }, opts);
}

// ── Phase A.3: New MCP-supporting client functions ────────────────────────

export function chronomindTimerReschedule(
  timerId: string,
  input: { deltaSeconds?: number; targetTime?: string; syncVersion: number },
  opts: ChronoMindClientOptions
): Promise<TimerDoc> {
  return chronomindFetch(
    `/timers/${timerId}/reschedule`,
    { method: 'POST', body: JSON.stringify(input) },
    opts
  );
}

export interface FreeSlot {
  start: string;
  end: string;
  durationMinutes: number;
}

export function chronomindTimerAvailability(
  params: { start: string; end: string; minSlotMinutes?: number },
  opts: ChronoMindClientOptions
): Promise<{ slots: FreeSlot[]; totalFreeMinutes: number }> {
  const qs = new URLSearchParams();
  qs.set('start', params.start);
  qs.set('end', params.end);
  if (params.minSlotMinutes !== undefined) qs.set('minSlotMinutes', String(params.minSlotMinutes));
  return chronomindFetch(`/timers/availability?${qs.toString()}`, { method: 'GET' }, opts);
}

export function chronomindRoutineStart(
  routineId: string,
  opts: ChronoMindClientOptions
): Promise<RoutineDoc> {
  return chronomindFetch(`/routines/${routineId}/start`, { method: 'POST' }, opts);
}

// ── Agent Actions ─────────────────────────────────────────────────────────

export interface AgentActionDoc {
  id: string;
  userId: string;
  productId: string;
  actorId: string;
  actorType: 'agent' | 'user' | 'mcp';
  toolName: string;
  actionType: string;
  state: 'proposed' | 'approved' | 'applied' | 'rejected';
  reason?: string;
  payload: Record<string, unknown>;
  createdAt: string;
  reviewedAt?: string;
  reviewedBy?: string;
}

export function chronomindAgentActionCreate(
  input: {
    id: string;
    actorId: string;
    actorType: 'agent' | 'user' | 'mcp';
    toolName: string;
    actionType: string;
    state?: string;
    reason?: string;
    payload?: Record<string, unknown>;
  },
  opts: ChronoMindClientOptions
): Promise<AgentActionDoc> {
  return chronomindFetch('/agent-actions', { method: 'POST', body: JSON.stringify(input) }, opts);
}

export function chronomindAgentActionsList(
  params: { state?: string; actorId?: string; toolName?: string; limit?: number; offset?: number },
  opts: ChronoMindClientOptions
): Promise<{ items: AgentActionDoc[]; total: number }> {
  const qs = new URLSearchParams();
  if (params.state) qs.set('state', params.state);
  if (params.actorId) qs.set('actorId', params.actorId);
  if (params.toolName) qs.set('toolName', params.toolName);
  if (params.limit !== undefined) qs.set('limit', String(params.limit));
  if (params.offset !== undefined) qs.set('offset', String(params.offset));
  const q = qs.toString();
  return chronomindFetch(`/agent-actions${q ? `?${q}` : ''}`, { method: 'GET' }, opts);
}

export function chronomindAgentActionApprove(
  actionId: string,
  opts: ChronoMindClientOptions
): Promise<AgentActionDoc> {
  return chronomindFetch(`/agent-actions/${actionId}/approve`, { method: 'POST' }, opts);
}

// ── Phase B.2b: Day Planner MCP client functions ────────────────────────

export interface ProposedTimer {
  label: string;
  startTime: string;
  endTime: string;
  durationMinutes: number;
  priority: 'high' | 'medium' | 'low';
  urgency: string;
  category?: string;
  cascade: string;
}

export interface PlanDayResponse {
  planId: string;
  date: string;
  proposed: ProposedTimer[];
  overflow: ProposedTimer[];
  totalMinutesPlanned: number;
  totalMinutesOverflow: number;
  existingTimerCount: number;
}

export interface PlanNlResponse extends PlanDayResponse {
  parsedActivities: Array<{
    label: string;
    durationMinutes: number;
    priority: string;
    category?: string;
  }>;
  unparsed: string[];
}

export function chronomindPlannerPlanDay(
  input: {
    date: string;
    dayStartHour?: number;
    dayEndHour?: number;
    activities: Array<{
      label: string;
      durationMinutes: number;
      priority?: string;
      category?: string;
    }>;
    prepTimeMinutes?: number;
  },
  opts: ChronoMindClientOptions
): Promise<PlanDayResponse> {
  return chronomindFetch(
    '/planner/plan-day',
    { method: 'POST', body: JSON.stringify(input) },
    opts
  );
}

export function chronomindPlannerPlanNl(
  input: {
    text: string;
    date?: string;
    dayStartHour?: number;
    dayEndHour?: number;
    prepTimeMinutes?: number;
  },
  opts: ChronoMindClientOptions
): Promise<PlanNlResponse> {
  return chronomindFetch('/planner/plan-nl', { method: 'POST', body: JSON.stringify(input) }, opts);
}

export function chronomindPlannerApply(
  input: { planId: string; proposed: ProposedTimer[] },
  opts: ChronoMindClientOptions
): Promise<{ planId: string; created: string[] }> {
  return chronomindFetch(
    '/planner/apply-plan',
    { method: 'POST', body: JSON.stringify(input) },
    opts
  );
}

export function chronomindPlannerReplan(
  input: {
    planId: string;
    date: string;
    keep?: string[];
    drop?: string[];
    add?: Array<{ label: string; durationMinutes: number; priority?: string; category?: string }>;
    dayStartHour?: number;
    dayEndHour?: number;
    prepTimeMinutes?: number;
  },
  opts: ChronoMindClientOptions
): Promise<PlanDayResponse> {
  return chronomindFetch('/planner/replan', { method: 'POST', body: JSON.stringify(input) }, opts);
}
