import { ApiPermission } from "@prisma/client";
import { db } from "../db";
import { randomBytes } from "crypto";
import { smallNanoid } from "../nanoid";
import { createSecureHash, verifySecureHash } from "../crypto";
import { logger } from "../logger/log";

export async function addApiKey({
  name,
  permission,
  teamId,
  domainId,
}: {
  name: string;
  permission: ApiPermission;
  teamId: number;
  domainId?: number;
}) {
  try {
    // Validate domain ownership if domainId is provided
    if (domainId !== undefined) {
      const domain = await db.domain.findUnique({
        where: { 
          id: domainId,
          teamId: teamId 
        },
        select: { id: true },
      });
      
      if (!domain) {
        throw new Error("DOMAIN_NOT_FOUND");
      }
    }

    const clientId = smallNanoid(10);
    const token = randomBytes(16).toString("hex");
    const hashedToken = await createSecureHash(token);

    const apiKey = `us_${clientId}_${token}`;

    await db.apiKey.create({
      data: {
        name,
        permission: permission,
        teamId,
        domainId,
        tokenHash: hashedToken,
        partialToken: `${apiKey.slice(0, 6)}...${apiKey.slice(-3)}`,
        clientId,
      },
    });
    return apiKey;
  } catch (error) {
    logger.error({ err: error }, "Error adding API key");
    throw error;
  }
}

export async function getTeamAndApiKey(apiKey: string) {
  const [, clientId, token] = apiKey.split("_") as [string, string, string];

  const apiKeyRow = await db.apiKey.findUnique({
    where: {
      clientId,
    },
    include: {
      domain: {
        select: { id: true, name: true },
      },
    },
  });

  if (!apiKeyRow) {
    return null;
  }

  try {
    const isValid = await verifySecureHash(token, apiKeyRow.tokenHash);
    if (!isValid) {
      return null;
    }

    const team = await db.team.findUnique({
      where: {
        id: apiKeyRow.teamId,
      },
    });

    return { team, apiKey: apiKeyRow };
  } catch (error) {
    logger.error({ err: error }, "Error verifying API key");
    return null;
  }
}

export async function updateApiKey({
  id,
  teamId,
  name,
  domainId,
}: {
  id: number;
  teamId: number;
  name?: string;
  domainId?: number | null;
}) {
  try {
    if (domainId !== undefined && domainId !== null) {
      const domain = await db.domain.findUnique({
        where: {
          id: domainId,
          teamId: teamId,
        },
        select: { id: true },
      });

      if (!domain) {
        throw new Error("DOMAIN_NOT_FOUND");
      }
    }

    return await db.apiKey.update({
      where: { id, teamId },
      data: {
        ...(name !== undefined && { name }),
        ...(domainId !== undefined && { domainId }),
      },
    });
  } catch (error) {
    logger.error({ err: error }, "Error updating API key");
    throw error;
  }
}

export async function deleteApiKey(id: number) {
  try {
    await db.apiKey.delete({
      where: {
        id,
      },
    });
  } catch (error) {
    logger.error({ err: error }, "Error deleting API key");
    throw error;
  }
}
