import { redirectToLoginAfterSessionExpired } from "@/features/auth/service/auth-service";

// --- Shapes returned by GET /dashboard/working-group ------------------------
// These mirror the backend response types one-to-one (see
// backend/src/modules/dashboard/dashboard.service.ts).

type ApiResponse<T> = {
  success: boolean;
  statusCode: number;
  message: string;
  data: T;
};

// One status slice, e.g. { statusId: 5, code: "SOLVED", name: "Solved", count: 2 }.
// Reused by the donut chart and by each stacked bar.
export type DashboardStatusCount = {
  statusId: number;
  code: string;
  name: string;
  count: number;
};

// The five numbers shown in the summary cards row.
export type DashboardCards = {
  totalIssues: number;
  solved: number;
  inProgress: number;
  notAddressed: number;
  totalPrimaryAgencies: number;
};

// One bar in the "issues per primary government agency" chart.
export type DashboardAgencyRow = {
  agencyId: number;
  agencyName: string;
  total: number;
  byStatus: DashboardStatusCount[];
};

// One bar in the "issues per working group" chart.
export type DashboardWorkingGroupRow = {
  workingGroupId: number;
  workingGroupName: string;
  total: number;
  byStatus: DashboardStatusCount[];
};

// One bar in the "issues per category" chart.
export type DashboardCategoryRow = {
  categoryId: number;
  categoryName: string;
  count: number;
};

// The full dashboard payload.
export type DashboardSummary = {
  cards: DashboardCards;
  statusBreakdown: DashboardStatusCount[];
  byPrimaryAgency: DashboardAgencyRow[];
  byWorkingGroup: DashboardWorkingGroupRow[];
  byCategory: DashboardCategoryRow[];
};

// Filters we can send to the backend. Every field is optional; a missing
// field means "do not filter by this".
export type DashboardSummaryParams = {
  year?: number;
  issueStatusId?: number;
  primaryAgencyId?: number;
  categoryId?: number;
  workingGroupId?: number;
};

const API_URL =
  process.env.NEXT_PUBLIC_API_URL || "http://localhost:3001/api/v1";

function getApiErrorMessage(body: unknown, status: number) {
  if (body && typeof body === "object" && "message" in body) {
    const message = (body as { message?: unknown }).message;

    if (Array.isArray(message)) return message.join(" ");
    if (typeof message === "string" && message.trim()) return message;
  }

  if (status === 401) return "Unauthorized";
  if (status === 403) {
    return "You do not have permission to view the dashboard.";
  }

  return `Unable to load the dashboard (${status}).`;
}

async function parseResponseBody(response: Response) {
  const text = await response.text();
  if (!text) return null;

  try {
    return JSON.parse(text) as unknown;
  } catch {
    return text;
  }
}

async function getRequest<T>(path: string): Promise<T> {
  const response = await fetch(`${API_URL}${path}`, {
    method: "GET",
    credentials: "include",
    headers: {
      "Content-Type": "application/json",
    },
  });
  const responseBody = await parseResponseBody(response);

  if (!response.ok) {
    if (response.status === 401) {
      redirectToLoginAfterSessionExpired();
    }

    throw new Error(getApiErrorMessage(responseBody, response.status));
  }

  return responseBody as T;
}

// Builds "?year=2026&categoryId=2" from the params object. Fields that are
// undefined are skipped entirely — the backend rejects unknown or empty
// params with a 400, so we only ever send real values.
function buildQueryString(params: DashboardSummaryParams) {
  const searchParams = new URLSearchParams();

  if (params.year !== undefined) {
    searchParams.set("year", String(params.year));
  }
  if (params.issueStatusId !== undefined) {
    searchParams.set("issueStatusId", String(params.issueStatusId));
  }
  if (params.primaryAgencyId !== undefined) {
    searchParams.set("primaryAgencyId", String(params.primaryAgencyId));
  }
  if (params.categoryId !== undefined) {
    searchParams.set("categoryId", String(params.categoryId));
  }
  if (params.workingGroupId !== undefined) {
    searchParams.set("workingGroupId", String(params.workingGroupId));
  }

  const queryString = searchParams.toString();
  return queryString ? `?${queryString}` : "";
}

export async function getDashboardSummary(
  params: DashboardSummaryParams,
): Promise<DashboardSummary> {
  const response = await getRequest<ApiResponse<DashboardSummary>>(
    `/dashboard/working-group${buildQueryString(params)}`,
  );

  return response.data;
}
