/**
 * ThirdEye API Client
 * Connects to the FastAPI backend at localhost:8000 (proxied via /api)
 */

const API_BASE = "/api";

// ─── Types ────────────────────────────────────────────────────────────────────

export interface SignalMetadata {
  type: string;
  severity: "low" | "medium" | "high" | "critical";
  status: string;
  sentiment: string;
  urgency: string;
  entities: string; // JSON string
  keywords: string; // JSON string
  raw_quote: string;
  timestamp: string;
  group_id: string;
  lens: string;
  meeting_id?: string;
}

export interface Signal {
  document: string;
  metadata: SignalMetadata;
  id: string;
}

export interface Group {
  group_id: string;
  group_name: string;
  signal_count: number;
  lens: string;
}

export interface Pattern {
  id: string;
  group_id: string;
  type: string;
  description: string;
  severity: "info" | "warning" | "critical";
  evidence_signal_ids: string[];
  recommendation: string;
  detected_at: string;
  is_active: boolean;
}

export interface CrossGroupInsight {
  id: string;
  type: string;
  description: string;
  group_a: { name?: string; group_id?: string; evidence?: string };
  group_b: { name?: string; group_id?: string; evidence?: string };
  severity: string;
  recommendation: string;
  detected_at: string;
  is_resolved: boolean;
}

export interface Meeting {
  meeting_id: string;
  signal_count: number;
  types: Record<string, number>;
  started_at?: string;
  speaker?: string;
  group_id?: string;
}

export interface MeetingDetail {
  meeting_id: string;
  started_at: string;
  speaker: string;
  group_id: string;
  total_signals: number;
  signal_counts: Record<string, number>;
  summary: string;
}

export interface TranscriptChunk {
  id: string;
  text: string;
  speaker: string;
  timestamp: string;
  summary: string;
}

export interface JiraTicket {
  id: string;
  jira_key: string;
  jira_url: string;
  jira_summary: string;
  jira_priority: string;
  original_signal_id: string;
  group_id: string;
  raised_at: string;
  status: string;
  assignee?: string;
}

export interface JiraConfig {
  configured: boolean;
  connected?: boolean;
  base_url?: string;
  default_project?: string;
  projects?: { key: string; name: string; id: string }[];
}

export interface TimelineSignal extends Signal {
  group_name?: string;
}

// ─── Helpers ──────────────────────────────────────────────────────────────────

async function fetchJSON<T>(url: string, options?: RequestInit): Promise<T> {
  const res = await fetch(url, options);
  if (!res.ok) {
    throw new Error(`API error ${res.status}: ${await res.text()}`);
  }
  return res.json() as Promise<T>;
}

// ─── Groups ───────────────────────────────────────────────────────────────────

export async function fetchGroups(): Promise<Group[]> {
  const data = await fetchJSON<{ groups: Group[] }>(`${API_BASE}/groups`);
  return data.groups;
}

// ─── Signals ──────────────────────────────────────────────────────────────────

export async function fetchSignals(
  groupId: string,
  signalType?: string
): Promise<Signal[]> {
  const url = signalType
    ? `${API_BASE}/groups/${groupId}/signals?signal_type=${signalType}`
    : `${API_BASE}/groups/${groupId}/signals`;
  const data = await fetchJSON<{ signals: Signal[]; count: number }>(url);
  return data.signals;
}

export async function fetchAllSignals(): Promise<{ group_id: string; signals: Signal[] }[]> {
  const groups = await fetchGroups();
  const results = await Promise.allSettled(
    groups.map(async (g) => ({
      group_id: g.group_id,
      signals: await fetchSignals(g.group_id),
    }))
  );
  return results
    .filter(
      (r): r is PromiseFulfilledResult<{ group_id: string; signals: Signal[] }> =>
        r.status === "fulfilled"
    )
    .map((r) => r.value);
}

// ─── Patterns ─────────────────────────────────────────────────────────────────

export async function fetchPatterns(groupId: string): Promise<Pattern[]> {
  const data = await fetchJSON<{ patterns: Pattern[] }>(
    `${API_BASE}/groups/${groupId}/patterns`
  );
  return data.patterns;
}

export async function fetchAllPatterns(): Promise<Pattern[]> {
  const groups = await fetchGroups();
  const results = await Promise.allSettled(groups.map((g) => fetchPatterns(g.group_id)));
  return results
    .filter((r): r is PromiseFulfilledResult<Pattern[]> => r.status === "fulfilled")
    .flatMap((r) => r.value);
}

// ─── Cross-Group Insights ─────────────────────────────────────────────────────

export async function fetchCrossGroupInsights(
  timeoutMs = 30000
): Promise<CrossGroupInsight[]> {
  const ctrl = new AbortController();
  const timer = setTimeout(() => ctrl.abort(), timeoutMs);
  try {
    const data = await fetchJSON<{ insights: CrossGroupInsight[]; message?: string }>(
      `${API_BASE}/cross-group/insights`,
      { signal: ctrl.signal }
    );
    return data.insights;
  } finally {
    clearTimeout(timer);
  }
}

// ─── Knowledge Base Query ─────────────────────────────────────────────────────

export async function queryKnowledge(
  groupId: string,
  question: string
): Promise<{ answer: string; question: string }> {
  return fetchJSON(`${API_BASE}/groups/${groupId}/query`, {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({ question }),
  });
}

// ─── Meetings ─────────────────────────────────────────────────────────────────

export async function fetchMeetings(): Promise<Meeting[]> {
  const data = await fetchJSON<{ meetings: Meeting[] }>(`${API_BASE}/meet/meetings`);
  return data.meetings;
}

export async function fetchMeetingDetail(meetingId: string): Promise<MeetingDetail> {
  return fetchJSON<MeetingDetail>(`${API_BASE}/meet/meetings/${encodeURIComponent(meetingId)}`);
}

export async function fetchMeetingTranscript(
  meetingId: string
): Promise<{ transcript: TranscriptChunk[]; chunk_count: number }> {
  return fetchJSON(`${API_BASE}/meet/meetings/${encodeURIComponent(meetingId)}/transcript`);
}

export async function fetchMeetingSignals(meetingId: string): Promise<Signal[]> {
  const data = await fetchJSON<{ signals: Signal[]; count: number }>(
    `${API_BASE}/meet/meetings/${encodeURIComponent(meetingId)}/signals`
  );
  return data.signals;
}

// ─── Jira ─────────────────────────────────────────────────────────────────────

export interface JiraTicketFilters {
  group_id?: string;
  date_from?: string;
  date_to?: string;
  live?: boolean;
}

export async function fetchJiraTickets(filters: JiraTicketFilters = {}): Promise<JiraTicket[]> {
  const params = new URLSearchParams();
  if (filters.group_id) params.set("group_id", filters.group_id);
  if (filters.date_from) params.set("date_from", filters.date_from);
  if (filters.date_to) params.set("date_to", filters.date_to);
  if (filters.live) params.set("live", "true");
  const url = params.toString()
    ? `${API_BASE}/jira/tickets?${params}`
    : `${API_BASE}/jira/tickets`;
  const data = await fetchJSON<{ tickets: JiraTicket[]; count: number }>(url);
  return data.tickets;
}

export async function fetchJiraTicketStatus(
  ticketKey: string
): Promise<{ key: string; status: string; assignee: string; summary: string; url: string }> {
  return fetchJSON(`${API_BASE}/jira/tickets/${encodeURIComponent(ticketKey)}/status`);
}

export async function raiseJiraTicket(
  signalId: string,
  groupId: string,
  projectKey?: string,
  force = false
): Promise<{ ok: boolean; key?: string; url?: string; summary?: string; reason?: string; error?: string }> {
  return fetchJSON(`${API_BASE}/jira/raise`, {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({ signal_id: signalId, group_id: groupId, project_key: projectKey, force }),
  });
}

export async function createJiraTicket(data: {
  summary: string;
  description?: string;
  project_key?: string;
  issue_type?: string;
  priority?: string;
  labels?: string[];
  assignee_account_id?: string;
}): Promise<{ ok: boolean; key?: string; url?: string; error?: string; details?: unknown }> {
  return fetchJSON(`${API_BASE}/jira/create`, {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify(data),
  });
}

export async function searchJiraUsers(
  query: string
): Promise<{ account_id: string; display_name: string; email: string; active: boolean }[]> {
  const data = await fetchJSON<{ users: { account_id: string; display_name: string; email: string; active: boolean }[] }>(
    `${API_BASE}/jira/users/search?q=${encodeURIComponent(query)}`
  );
  return data.users;
}

export async function fetchJiraConfig(): Promise<JiraConfig> {
  return fetchJSON<JiraConfig>(`${API_BASE}/jira/config`);
}

// ─── Timeline (cross-group signals) ──────────────────────────────────────────

export interface TimelineFilters {
  group_id?: string;
  severity?: string;
  lens?: string;
  signal_type?: string;
  date_from?: string;
  date_to?: string;
  limit?: number;
}

export async function fetchTimeline(
  filters: TimelineFilters = {}
): Promise<{ signals: TimelineSignal[]; total: number; truncated: boolean }> {
  const params = new URLSearchParams();
  Object.entries(filters).forEach(([k, v]) => {
    if (v !== undefined && v !== "") params.set(k, String(v));
  });
  const url = params.toString()
    ? `${API_BASE}/signals/timeline?${params}`
    : `${API_BASE}/signals/timeline`;
  return fetchJSON(url);
}

// ─── Knowledge Browser ───────────────────────────────────────────────────────

export interface KnowledgeTopicSummary {
  name: string;
  signal_count: number;
  latest: string;
  sample_signals: string[];
}

export interface KnowledgeDayEntry {
  date: string;
  signals: Signal[];
  topics: string[];
  signal_count: number;
}

export interface KnowledgeBrowseResponse {
  group_id: string;
  group_name: string;
  total_signals: number;
  date_range: { earliest: string; latest: string };
  topics: KnowledgeTopicSummary[];
  timeline: KnowledgeDayEntry[];
}

export async function fetchKnowledgeBrowse(
  groupId: string,
  options: { dateFrom?: string; dateTo?: string; topic?: string } = {}
): Promise<KnowledgeBrowseResponse> {
  const params = new URLSearchParams();
  if (options.dateFrom) params.set("date_from", options.dateFrom);
  if (options.dateTo) params.set("date_to", options.dateTo);
  if (options.topic) params.set("topic", options.topic);
  const qs = params.toString();
  return fetchJSON<KnowledgeBrowseResponse>(
    `${API_BASE}/knowledge/browse/${encodeURIComponent(groupId)}${qs ? `?${qs}` : ""}`
  );
}

// ─── Health ───────────────────────────────────────────────────────────────────

export async function checkHealth(): Promise<boolean> {
  try {
    await fetchJSON("/health");
    return true;
  } catch {
    return false;
  }
}

// ─── Utility ──────────────────────────────────────────────────────────────────

/** Format ISO timestamp to a relative "T-Xm ago" style string */
export function formatRelativeTime(isoString: string): string {
  const now = Date.now();
  const ts = new Date(isoString).getTime();
  const diffMs = now - ts;
  const diffS = Math.floor(diffMs / 1000);
  if (diffS < 60) return `T-${diffS}s ago`;
  const diffM = Math.floor(diffS / 60);
  if (diffM < 60) return `T-${diffM}m ago`;
  const diffH = Math.floor(diffM / 60);
  if (diffH < 24) return `T-${diffH}h ago`;
  const diffD = Math.floor(diffH / 24);
  return `T-${diffD}d ago`;
}

/** Get a severity color for a signal */
export function getSeverityColor(severity: string): string {
  switch (severity) {
    case "critical":
      return "#ff6f78";
    case "high":
      return "#ffb300";
    case "medium":
      return "#A78BFA";
    default:
      return "#A78BFA";
  }
}

/** Get an icon for a signal type */
export function getSignalIcon(type: string): string {
  const iconMap: Record<string, string> = {
    architecture_decision: "architecture",
    tech_debt: "construction",
    security_concern: "security",
    consensus: "check_circle",
    blocker: "block",
    risk: "warning",
    sentiment_spike: "mood",
    knowledge_gap: "help",
    decision: "gavel",
    action_item: "task_alt",
    trend: "trending_up",
    jira_raised: "bug_report",
    meet_started: "videocam",
    meet_transcript: "record_voice_over",
  };
  return iconMap[type] ?? "sensors";
}

/** Parse a JSON string field from signal metadata safely */
export function parseMetaList(str: string): string[] {
  try {
    const parsed = JSON.parse(str);
    return Array.isArray(parsed) ? parsed : [];
  } catch {
    return [];
  }
}
