/**
 * Knowledge API Client
 * Handles knowledge entry-related API requests
 */

import type {
  KnowledgeEntryWithTags,
  KnowledgeTag,
  KnowledgeEntryVersionWithAuthor,
  PaginatedResponse,
  EntryStatus,
  Visibility,
} from "@mosaic/shared";
import { apiGet, apiPost, apiPatch, apiDelete, type ApiResponse } from "./client";

export interface EntryFilters {
  status?: EntryStatus;
  visibility?: Visibility;
  tag?: string;
  tags?: string[];
  page?: number;
  limit?: number;
  search?: string;
  sortBy?: "updatedAt" | "createdAt" | "title";
  sortOrder?: "asc" | "desc";
}

export interface EntriesResponse {
  data: KnowledgeEntryWithTags[];
  meta?: {
    total?: number;
    page?: number;
    limit?: number;
  };
}

export interface CreateEntryData {
  title: string;
  content: string;
  summary?: string;
  status?: EntryStatus;
  visibility?: Visibility;
  tags?: string[];
}

export interface UpdateEntryData {
  title?: string;
  content?: string;
  summary?: string;
  status?: EntryStatus;
  visibility?: Visibility;
  tags?: string[];
  changeNote?: string;
}

export interface RestoreVersionData {
  changeNote?: string;
}

/**
 * Fetch knowledge entries with optional filters
 */
export async function fetchEntries(filters?: EntryFilters): Promise<EntriesResponse> {
  const params = new URLSearchParams();

  if (filters?.status) {
    params.append("status", filters.status);
  }
  if (filters?.visibility) {
    params.append("visibility", filters.visibility);
  }
  if (filters?.tag) {
    params.append("tag", filters.tag);
  }
  if (filters?.tags && filters.tags.length > 0) {
    filters.tags.forEach((tag) => {
      params.append("tags", tag);
    });
  }
  if (filters?.page) {
    params.append("page", filters.page.toString());
  }
  if (filters?.limit) {
    params.append("limit", filters.limit.toString());
  }
  if (filters?.search) {
    params.append("search", filters.search);
  }
  if (filters?.sortBy) {
    params.append("sortBy", filters.sortBy);
  }
  if (filters?.sortOrder) {
    params.append("sortOrder", filters.sortOrder);
  }

  const queryString = params.toString();
  const endpoint = queryString ? `/api/knowledge/entries?${queryString}` : "/api/knowledge/entries";

  const response = await apiGet<EntriesResponse>(endpoint);
  return response;
}

/**
 * Fetch a single knowledge entry by slug
 */
export async function fetchEntry(slug: string): Promise<KnowledgeEntryWithTags> {
  return apiGet<KnowledgeEntryWithTags>(`/api/knowledge/entries/${slug}`);
}

/**
 * Create a new knowledge entry
 */
export async function createEntry(data: CreateEntryData): Promise<KnowledgeEntryWithTags> {
  return apiPost<KnowledgeEntryWithTags>("/api/knowledge/entries", data);
}

/**
 * Update an existing knowledge entry
 */
export async function updateEntry(
  slug: string,
  data: UpdateEntryData
): Promise<KnowledgeEntryWithTags> {
  return apiPatch<KnowledgeEntryWithTags>(`/api/knowledge/entries/${slug}`, data);
}

/**
 * Delete (archive) a knowledge entry
 */
export async function deleteEntry(slug: string): Promise<void> {
  await apiDelete(`/api/knowledge/entries/${slug}`);
}

/**
 * Fetch all knowledge tags
 */
export async function fetchTags(): Promise<KnowledgeTag[]> {
  const response = await apiGet<ApiResponse<KnowledgeTag[]>>("/api/knowledge/tags");
  return response.data;
}

/**
 * Fetch version history for an entry
 */
export async function fetchVersions(
  slug: string,
  page = 1,
  limit = 20
): Promise<PaginatedResponse<KnowledgeEntryVersionWithAuthor>> {
  const params = new URLSearchParams();
  params.append("page", page.toString());
  params.append("limit", limit.toString());

  return apiGet<PaginatedResponse<KnowledgeEntryVersionWithAuthor>>(
    `/api/knowledge/entries/${slug}/versions?${params.toString()}`
  );
}

/**
 * Fetch a specific version of an entry
 */
export async function fetchVersion(
  slug: string,
  version: number
): Promise<KnowledgeEntryVersionWithAuthor> {
  return apiGet<KnowledgeEntryVersionWithAuthor>(
    `/api/knowledge/entries/${slug}/versions/${version.toString()}`
  );
}

/**
 * Restore a previous version of an entry
 */
export async function restoreVersion(
  slug: string,
  version: number,
  data?: RestoreVersionData
): Promise<KnowledgeEntryWithTags> {
  return apiPost<KnowledgeEntryWithTags>(
    `/api/knowledge/entries/${slug}/restore/${version.toString()}`,
    data ?? {}
  );
}

/**
 * Fetch backlinks for an entry (entries that link to this entry)
 */
export async function fetchBacklinks(slug: string): Promise<{
  entry: { id: string; slug: string; title: string };
  backlinks: {
    id: string;
    sourceId: string;
    targetId: string;
    linkText: string;
    displayText: string;
    positionStart: number;
    positionEnd: number;
    resolved: boolean;
    context: string | null;
    createdAt: Date;
    source: {
      id: string;
      title: string;
      slug: string;
      summary?: string | null;
    };
  }[];
  count: number;
}> {
  return apiGet<{
    entry: { id: string; slug: string; title: string };
    backlinks: {
      id: string;
      sourceId: string;
      targetId: string;
      linkText: string;
      displayText: string;
      positionStart: number;
      positionEnd: number;
      resolved: boolean;
      context: string | null;
      createdAt: Date;
      source: {
        id: string;
        title: string;
        slug: string;
        summary?: string | null;
      };
    }[];
    count: number;
  }>(`/api/knowledge/entries/${slug}/backlinks`);
}

/**
 * Fetch knowledge base statistics
 */
export async function fetchKnowledgeStats(): Promise<{
  overview: {
    totalEntries: number;
    totalTags: number;
    totalLinks: number;
    publishedEntries: number;
    draftEntries: number;
    archivedEntries: number;
  };
  mostConnected: {
    id: string;
    slug: string;
    title: string;
    incomingLinks: number;
    outgoingLinks: number;
    totalConnections: number;
  }[];
  recentActivity: {
    id: string;
    slug: string;
    title: string;
    updatedAt: string;
    status: string;
  }[];
  tagDistribution: {
    id: string;
    name: string;
    slug: string;
    color: string | null;
    entryCount: number;
  }[];
}> {
  return apiGet(`/api/knowledge/stats`);
}

/**
 * Fetch entry graph (network of connected entries)
 */
export async function fetchEntryGraph(
  slug: string,
  depth = 1
): Promise<{
  centerNode: {
    id: string;
    slug: string;
    title: string;
    summary: string | null;
    tags: {
      id: string;
      name: string;
      slug: string;
      color: string | null;
    }[];
    depth: number;
  };
  nodes: {
    id: string;
    slug: string;
    title: string;
    summary: string | null;
    tags: {
      id: string;
      name: string;
      slug: string;
      color: string | null;
    }[];
    depth: number;
  }[];
  edges: {
    id: string;
    sourceId: string;
    targetId: string;
    linkText: string;
  }[];
  stats: {
    totalNodes: number;
    totalEdges: number;
    maxDepth: number;
  };
}> {
  const params = new URLSearchParams();
  params.append("depth", depth.toString());
  return apiGet(`/api/knowledge/entries/${slug}/graph?${params.toString()}`);
}

/**
 * Fetch full knowledge graph
 */
export async function fetchKnowledgeGraph(filters?: {
  tags?: string[];
  status?: string;
  limit?: number;
}): Promise<{
  nodes: {
    id: string;
    slug: string;
    title: string;
    summary: string | null;
    status?: string;
    tags: {
      id: string;
      name: string;
      slug: string;
      color: string | null;
    }[];
    depth: number;
    isOrphan?: boolean;
  }[];
  edges: {
    id: string;
    sourceId: string;
    targetId: string;
    linkText: string;
  }[];
  stats: {
    totalNodes: number;
    totalEdges: number;
    orphanCount: number;
  };
}> {
  const params = new URLSearchParams();
  if (filters?.tags && filters.tags.length > 0) {
    filters.tags.forEach((tag) => {
      params.append("tags", tag);
    });
  }
  if (filters?.status) {
    params.append("status", filters.status);
  }
  if (filters?.limit !== undefined) {
    params.append("limit", filters.limit.toString());
  }

  const queryString = params.toString();
  const endpoint = queryString ? `/api/knowledge/graph?${queryString}` : "/api/knowledge/graph";
  return apiGet(endpoint);
}
