import { customFetch } from "@/api/mutator";

// Forgejo Connection types
export interface ForgejoConnection {
  id: string;
  organization_id: string;
  name: string;
  base_url: string;
  token: null; // Always null in responses
  active: boolean;
  has_token: boolean;
  token_last_eight: string | null;
  created_at: string;
  updated_at: string;
}

export interface ForgejoConnectionCreate {
  name: string;
  base_url: string;
  token: string;
}

export interface ForgejoConnectionUpdate {
  name?: string;
  base_url?: string;
  token?: string;
}

// Forgejo Repository types
export interface ForgejoRepoLabel {
  id: number | null;
  name: string;
  color: string;
  description: string;
}

export interface ForgejoRepository {
  id: string;
  organization_id: string;
  connection_id: string;
  owner: string;
  repo: string;
  display_name: string;
  default_branch: string;
  active: boolean;
  has_webhook_secret: boolean;
  description: string | null;
  open_issues_count: number;
  is_archived: boolean;
  topics: string[];
  labels: ForgejoRepoLabel[];
  connection: ForgejoConnection;
  last_sync_at: string | null;
  last_sync_error: string | null;
  created_at: string;
  updated_at: string;
}

export interface ForgejoRepositoryCreate {
  connection_id: string;
  owner: string;
  repo: string;
  display_name?: string;
  default_branch?: string;
}

export interface ForgejoRepositoryUpdate {
  display_name?: string;
  default_branch?: string;
  webhook_secret?: string | null;
}

type ApiResponse<T> = {
  data: T;
  status: number;
  headers: Headers;
};

async function fetchJson<T>(path: string, init?: RequestInit): Promise<T> {
  const response = await customFetch<ApiResponse<T>>(path, init ?? {});
  return response.data;
}

// Forgejo Connection API
export async function getForgejoConnections(): Promise<ForgejoConnection[]> {
  return fetchJson<ForgejoConnection[]>("/api/v1/forgejo/connections");
}

export async function createForgejoConnection(
  data: ForgejoConnectionCreate,
): Promise<ForgejoConnection> {
  return fetchJson<ForgejoConnection>("/api/v1/forgejo/connections", {
    method: "POST",
    body: JSON.stringify(data),
  });
}

export async function getForgejoConnection(
  connectionId: string,
): Promise<ForgejoConnection> {
  return fetchJson<ForgejoConnection>(
    `/api/v1/forgejo/connections/${connectionId}`,
  );
}

export async function updateForgejoConnection(
  connectionId: string,
  data: ForgejoConnectionUpdate,
): Promise<ForgejoConnection> {
  return fetchJson<ForgejoConnection>(
    `/api/v1/forgejo/connections/${connectionId}`,
    {
      method: "PATCH",
      body: JSON.stringify(data),
    },
  );
}

export async function deleteForgejoConnection(
  connectionId: string,
): Promise<void> {
  await customFetch<ApiResponse<unknown>>(
    `/api/v1/forgejo/connections/${connectionId}`,
    {
      method: "DELETE",
    },
  );
}

// Forgejo Repository API
export async function getForgejoRepositories(): Promise<ForgejoRepository[]> {
  return fetchJson<ForgejoRepository[]>("/api/v1/forgejo/repositories");
}

export async function createForgejoRepository(
  data: ForgejoRepositoryCreate,
): Promise<ForgejoRepository> {
  return fetchJson<ForgejoRepository>("/api/v1/forgejo/repositories", {
    method: "POST",
    body: JSON.stringify(data),
  });
}

export async function getForgejoRepository(
  repositoryId: string,
): Promise<ForgejoRepository> {
  return fetchJson<ForgejoRepository>(
    `/api/v1/forgejo/repositories/${repositoryId}`,
  );
}

export async function updateForgejoRepository(
  repositoryId: string,
  data: ForgejoRepositoryUpdate,
): Promise<ForgejoRepository> {
  return fetchJson<ForgejoRepository>(
    `/api/v1/forgejo/repositories/${repositoryId}`,
    {
      method: "PATCH",
      body: JSON.stringify(data),
    },
  );
}

export async function deleteForgejoRepository(
  repositoryId: string,
): Promise<void> {
  await customFetch<ApiResponse<unknown>>(
    `/api/v1/forgejo/repositories/${repositoryId}`,
    {
      method: "DELETE",
    },
  );
}

// Pre-save connection test
export interface ForgejoConnectionTestRepo {
  full_name: string;
  name: string;
  owner: string;
  default_branch: string;
  private: boolean;
  description: string | null;
}

export interface ForgejoConnectionTestResult {
  valid: boolean;
  user_login: string | null;
  user_full_name: string | null;
  repo_count: number;
  repos: ForgejoConnectionTestRepo[];
  error: string | null;
  response_time_ms: number;
}

export async function testForgejoConnection(data: {
  base_url: string;
  token: string;
}): Promise<ForgejoConnectionTestResult> {
  return fetchJson<ForgejoConnectionTestResult>(
    "/api/v1/forgejo/connections/test",
    {
      method: "POST",
      body: JSON.stringify(data),
    },
  );
}

// Remote repo discovery
export interface ForgejoRemoteRepo {
  full_name: string;
  name: string;
  owner: string;
  default_branch: string;
  description: string | null;
  private: boolean;
  html_url: string;
}

export async function getConnectionRepos(
  connectionId: string,
): Promise<ForgejoRemoteRepo[]> {
  return fetchJson<ForgejoRemoteRepo[]>(
    `/api/v1/forgejo/connections/${connectionId}/repos`,
  );
}

// Forgejo Sync & Validation API
export async function syncRepository(repositoryId: string): Promise<{
  created: number;
  updated: number;
  open: number;
  closed: number;
  total: number;
}> {
  return fetchJson<{
    created: number;
    updated: number;
    open: number;
    closed: number;
    total: number;
  }>(`/api/v1/forgejo/repositories/${repositoryId}/sync`, {
    method: "POST",
  });
}

export interface ForgejoValidationStatus {
  ok: boolean;
  status: string;
  error_message?: string | null;
}

export interface ForgejoConnectionValidationResponse {
  connection_id: string;
  status: ForgejoValidationStatus;
  response_time_ms: number;
  validated_at: string;
}

export interface ForgejoRepositoryValidationResponse {
  repository_id: string;
  status: ForgejoValidationStatus;
  response_time_ms: number;
  validated_at: string;
  repo_exists?: boolean | null;
}

export async function validateConnection(
  connectionId: string,
): Promise<ForgejoConnectionValidationResponse> {
  return fetchJson<ForgejoConnectionValidationResponse>(
    `/api/v1/forgejo/connections/${connectionId}/validate`,
    {
      method: "POST",
    },
  );
}

export async function validateRepository(
  repositoryId: string,
): Promise<ForgejoRepositoryValidationResponse> {
  return fetchJson<ForgejoRepositoryValidationResponse>(
    `/api/v1/forgejo/repositories/${repositoryId}/validate`,
    {
      method: "POST",
    },
  );
}

// Forgejo Issue types
export interface ForgejoIssueLabel {
  id?: number | null;
  name: string;
  color: string;
  description?: string | null;
}

export interface ForgejoIssueMilestone {
  id: number | null;
  title: string;
  state: string;
  description: string | null;
  due_on: string | null;
  closed_at: string | null;
}

export interface ForgejoIssue {
  id: string;
  organization_id: string;
  repository_id: string;
  forgejo_issue_number: number;
  title: string;
  body: string | null;
  body_preview: string | null;
  state: string;
  is_pull_request: boolean;
  labels: ForgejoIssueLabel[];
  assignees: Record<string, unknown>[];
  milestone: ForgejoIssueMilestone | null;
  author: string;
  html_url: string;
  forgejo_created_at: string;
  forgejo_updated_at: string;
  forgejo_closed_at: string | null;
  last_synced_at: string;
  created_at: string;
  updated_at: string;
}

export interface ForgejoIssueListResponse {
  items: ForgejoIssue[];
  total: number;
  page: number;
  limit: number;
}

// Forgejo Issue API
export async function getForgejoIssues(params?: {
  repository_id?: string;
  board_id?: string;
  state?: string;
  search?: string;
  page?: number;
  limit?: number;
}): Promise<ForgejoIssueListResponse> {
  const searchParams = new URLSearchParams();
  if (params?.repository_id)
    searchParams.set("repository_id", params.repository_id);
  if (params?.board_id) searchParams.set("board_id", params.board_id);
  if (params?.state) searchParams.set("state", params.state);
  if (params?.search) searchParams.set("search", params.search);
  if (params?.page) searchParams.set("page", params.page.toString());
  if (params?.limit) searchParams.set("limit", params.limit.toString());

  const qs = searchParams.toString();
  return fetchJson<ForgejoIssueListResponse>(
    `/api/v1/forgejo/issues${qs ? `?${qs}` : ""}`,
  );
}

export async function getForgejoIssue(issueId: string): Promise<ForgejoIssue> {
  return fetchJson<ForgejoIssue>(`/api/v1/forgejo/issues/${issueId}`);
}

export async function closeForgejoIssue(
  issueId: string,
): Promise<ForgejoIssue> {
  return fetchJson<ForgejoIssue>(`/api/v1/forgejo/issues/${issueId}/close`, {
    method: "POST",
  });
}

// Board Repository Linking API
export interface BoardForgejoRepositoryLink {
  id: string;
  board_id: string;
  repository_id: string;
  organization_id: string;
  created_at: string;
  repository?: ForgejoRepository;
}

export type BoardForgejoRepositoriesResponse =
  | BoardForgejoRepositoryLink[]
  | { repositories: BoardForgejoRepositoryLink[] };

export async function getBoardForgejoRepositories(
  boardId: string,
): Promise<BoardForgejoRepositoriesResponse> {
  return fetchJson<BoardForgejoRepositoriesResponse>(
    `/api/v1/boards/${boardId}/forgejo/repositories`,
  );
}

export async function linkBoardForgejoRepository(
  boardId: string,
  repositoryId: string,
): Promise<BoardForgejoRepositoryLink | { link?: BoardForgejoRepositoryLink }> {
  return fetchJson<
    BoardForgejoRepositoryLink | { link?: BoardForgejoRepositoryLink }
  >(`/api/v1/boards/${boardId}/forgejo/repositories`, {
    method: "POST",
    body: JSON.stringify({ repository_id: repositoryId }),
  });
}

export async function unlinkBoardForgejoRepository(
  boardId: string,
  repositoryId: string,
): Promise<void> {
  await customFetch<ApiResponse<unknown>>(
    `/api/v1/boards/${boardId}/forgejo/repositories/${repositoryId}`,
    {
      method: "DELETE",
    },
  );
}

// Forgejo Metrics types
export interface RepositorySyncHealth {
  repository_id: string;
  owner: string;
  repo: string;
  display_name: string | null;
  last_sync_at: string | null;
  last_sync_error: string | null;
  has_error: boolean;
}

export interface ForgejoIssueMetrics {
  open_issues: number;
  closed_issues: number;
  closed_last_7_days: number;
  closed_last_30_days: number;
  stale_open_issues: number;
  repositories_synced: number;
  last_sync_timestamps: Record<string, string>;
  sync_error_counts: Record<string, number>;
}

// Forgejo Heatmap API
export interface ForgejoHeatmapDay {
  date: string; // "YYYY-MM-DD"
  count: number;
}

export interface ForgejoHeatmapResponse {
  days: ForgejoHeatmapDay[];
  max_count: number;
}

export async function getForgejoHeatmap(params?: {
  organization_id?: string;
}): Promise<ForgejoHeatmapResponse> {
  const searchParams = new URLSearchParams();
  if (params?.organization_id)
    searchParams.set("organization_id", params.organization_id);
  const qs = searchParams.toString();
  return fetchJson<ForgejoHeatmapResponse>(
    `/api/v1/forgejo/heatmap${qs ? `?${qs}` : ""}`,
  );
}

// Forgejo Metrics API
export async function getForgejoMetrics(params?: {
  organization_id?: string;
  board_id?: string;
  repository_id?: string;
}): Promise<ForgejoIssueMetrics> {
  const searchParams = new URLSearchParams();
  if (params?.organization_id)
    searchParams.set("organization_id", params.organization_id);
  if (params?.board_id) searchParams.set("board_id", params.board_id);
  if (params?.repository_id)
    searchParams.set("repository_id", params.repository_id);
  const qs = searchParams.toString();
  return fetchJson<ForgejoIssueMetrics>(
    `/api/v1/forgejo/metrics${qs ? `?${qs}` : ""}`,
  );
}
