import type { APIRoute } from "astro";
import { Octokit } from "@octokit/rest";
import { configs, db, repositories } from "@/lib/db";
import { v4 as uuidv4 } from "uuid";
import { and, eq } from "drizzle-orm";
import { type Repository } from "@/lib/db/schema";
import { jsonResponse, createSecureErrorResponse } from "@/lib/utils";
import type {
  AddRepositoriesApiRequest,
  AddRepositoriesApiResponse,
  RepositoryVisibility,
} from "@/types/Repository";
import { createMirrorJob } from "@/lib/helpers";

export const POST: APIRoute = async ({ request }) => {
  try {
    const body: AddRepositoriesApiRequest = await request.json();
    const { owner, repo, userId } = body;

    if (!owner || !repo || !userId) {
      return new Response(
        JSON.stringify({
          success: false,
          error: "Missing owner, repo, or userId",
        }),
        { status: 400 }
      );
    }

    // Check if repository with the same owner, name, and userId already exists
    const existingRepo = await db
      .select()
      .from(repositories)
      .where(
        and(
          eq(repositories.owner, owner),
          eq(repositories.name, repo),
          eq(repositories.userId, userId)
        )
      );

    if (existingRepo.length > 0) {
      return jsonResponse({
        data: {
          success: false,
          error:
            "Repository with this name and owner already exists for this user",
        },
        status: 400,
      });
    }

    // Get user's active config
    const [config] = await db
      .select()
      .from(configs)
      .where(eq(configs.userId, userId))
      .limit(1);

    if (!config) {
      return jsonResponse({
        data: { error: "No configuration found for this user" },
        status: 404,
      });
    }

    const configId = config.id;

    const octokit = new Octokit(); // No auth for public repos

    const { data: repoData } = await octokit.rest.repos.get({ owner, repo });

    const metadata = {
      id: uuidv4(),
      userId,
      configId,
      name: repoData.name,
      fullName: repoData.full_name,
      url: repoData.html_url,
      cloneUrl: repoData.clone_url,
      owner: repoData.owner.login,
      organization:
        repoData.owner.type === "Organization" ? repoData.owner.login : null,
      isPrivate: repoData.private,
      isForked: repoData.fork,
      forkedFrom: null,
      hasIssues: repoData.has_issues,
      isStarred: false,
      isArchived: repoData.archived,
      size: repoData.size,
      hasLFS: false,
      hasSubmodules: false,
      language: repoData.language ?? null,
      description: repoData.description ?? null,
      defaultBranch: repoData.default_branch,
      visibility: (repoData.visibility ?? "public") as RepositoryVisibility,
      status: "imported" as Repository["status"],
      lastMirrored: null,
      errorMessage: null,
      mirroredLocation: "",
      destinationOrg: null,
      createdAt: repoData.created_at
        ? new Date(repoData.created_at)
        : new Date(),
      updatedAt: repoData.updated_at
        ? new Date(repoData.updated_at)
        : new Date(),
    };

    await db
      .insert(repositories)
      .values(metadata)
      .onConflictDoNothing({ target: [repositories.userId, repositories.fullName] });

    createMirrorJob({
      userId,
      organizationId: metadata.organization,
      organizationName: metadata.organization,
      repositoryId: metadata.id,
      repositoryName: metadata.name,
      status: "imported",
      message: `Repository ${metadata.name} fetched successfully`,
      details: `Repository ${metadata.name} was fetched from GitHub`,
    });

    const resPayload: AddRepositoriesApiResponse = {
      success: true,
      repository: metadata,
      message: "Repository added successfully",
    };

    return jsonResponse({ data: resPayload, status: 200 });
  } catch (error) {
    return createSecureErrorResponse(error, "repository sync", 500);
  }
};
