export interface GiteaRepoInfo {
  languages: string[];
  updatedAt: string;
  size: number;
  defaultBranch: string;
  topics: string[];
  avatarUrl?: string;
}

export interface GiteaConfig {
  domain: string;
  owner: string;
  repo: string;
}

export function parseGiteaUrl(url: string): GiteaConfig | null {
  try {
    const urlObj = new URL(url);
    const pathParts = urlObj.pathname.split("/").filter((p) => p);

    if (pathParts.length >= 2) {
      return {
        domain: urlObj.origin,
        owner: pathParts[0],
        repo: pathParts[1],
      };
    }
  } catch (e) {
    // Invalid URL
  }
  return null;
}

export async function fetchGiteaRepoInfo(
  config: GiteaConfig,
): Promise<GiteaRepoInfo | null> {
  try {
    const apiUrl = `${config.domain}/api/v1/repos/${config.owner}/${config.repo}`;

    const response = await fetch(apiUrl, {
      headers: {
        Accept: "application/json",
      },
      signal: AbortSignal.timeout(5000),
    });

    if (!response.ok) {
      return null;
    }

    const data = await response.json();

    let languages: string[] = [];
    try {
      const languagesUrl = `${config.domain}/api/v1/repos/${config.owner}/${config.repo}/languages`;
      const languagesResponse = await fetch(languagesUrl, {
        headers: {
          Accept: "application/json",
        },
        signal: AbortSignal.timeout(5000),
      });
      if (languagesResponse.ok) {
        const languagesData = await languagesResponse.json();
        languages = Object.keys(languagesData).sort(
          (a, b) => languagesData[b] - languagesData[a],
        );
      }
    } catch (error) {
      // Ignore
    }

    return {
      languages: languages.length > 0 ? languages : [],
      updatedAt: data.updated_at || data.pushed_at || "",
      size: data.size || 0,
      defaultBranch: data.default_branch || "main",
      topics: Array.isArray(data.topics) ? data.topics : [],
      avatarUrl: data.avatar_url,
    };
  } catch (error) {
    return null;
  }
}

export async function fetchGiteaInfoFromUrl(
  url: string,
): Promise<GiteaRepoInfo | null> {
  const config = parseGiteaUrl(url);
  if (!config) {
    return null;
  }
  return fetchGiteaRepoInfo(config);
}

const MINUTE_MS = 60_000;
const HOUR_MS = 3_600_000;
const DAY_MS = 86_400_000;

const pluralize = (n: number, unit: string) =>
  `${n} ${unit}${n !== 1 ? "s" : ""} ago`;

export function formatRelativeTime(dateString: string): string {
  if (!dateString) return "Unknown";

  const diffMs = Date.now() - new Date(dateString).getTime();
  const diffMinutes = Math.floor(diffMs / MINUTE_MS);
  const diffHours = Math.floor(diffMs / HOUR_MS);
  const diffDays = Math.floor(diffMs / DAY_MS);

  if (diffMinutes < 60) return pluralize(diffMinutes, "minute");
  if (diffHours < 24) return pluralize(diffHours, "hour");
  if (diffDays < 30) return pluralize(diffDays, "day");
  if (diffDays < 365) return pluralize(Math.floor(diffDays / 30), "month");
  return pluralize(Math.floor(diffDays / 365), "year");
}

export function formatRepoSize(sizeKb: number): string {
  if (sizeKb < 1024) {
    return `${sizeKb} KB`;
  } else if (sizeKb < 1024 * 1024) {
    return `${(sizeKb / 1024).toFixed(1)} MB`;
  } else {
    return `${(sizeKb / (1024 * 1024)).toFixed(1)} GB`;
  }
}
