import { prisma } from "../constants";
import { CredentialTypeController } from "../controllers/CredentialTypeController";
import { CredentialTypeField } from "../modules/credentials/credentialTypeDefs";
import GenericError from "../Errors/GenericError";
import { Prisma } from "@prisma/client";

export const credentialTypes = {
  /**
   * Fetch Credential Type
   *
   * Fetch a credential type by its ID or name and return a CredentialTypeController instance.
   *
   * @param identifier - The credential type ID or name to fetch
   * @returns {Promise<CredentialTypeController>} - The credential type controller
   */
  async fetch(identifier: string): Promise<CredentialTypeController> {
    const credentialType = await prisma.credentialType.findFirst({
      where: {
        OR: [{ id: identifier }, { name: identifier }],
      },
      include: {
        credentials: true,
      },
    });

    if (!credentialType) {
      throw new GenericError({
        message: "Credential type not found",
        name: "CredentialTypeNotFound",
        cause: `No credential type exists with identifier '${identifier}'`,
        status: 404,
      });
    }

    return new CredentialTypeController(credentialType);
  },

  /**
   * Fetch All Credential Types
   *
   * Fetch all credential types in the system.
   *
   * @returns {Promise<CredentialTypeController[]>} - Array of credential type controllers
   */
  async fetchAll(): Promise<CredentialTypeController[]> {
    const credentialTypesList = await prisma.credentialType.findMany({
      include: {
        credentials: true,
      },
    });

    return credentialTypesList.map((ct) => new CredentialTypeController(ct));
  },

  /**
   * Create Credential Type
   *
   * Create a new credential type with its field definitions.
   *
   * @param data - The credential type data to create
   * @returns {Promise<CredentialTypeController>} - The created credential type controller
   */
  async create(data: {
    name: string;
    permissionScope: string;
    fields: CredentialTypeField[];
    icon?: string;
  }): Promise<CredentialTypeController> {
    // Check if a credential type with this name already exists
    const existing = await prisma.credentialType.findFirst({
      where: { name: data.name },
    });

    if (existing) {
      throw new GenericError({
        message: "Credential type name already exists",
        name: "CredentialTypeAlreadyExists",
        cause: `A credential type with name '${data.name}' already exists`,
        status: 400,
      });
    }

    const credentialType = await prisma.credentialType.create({
      data: {
        name: data.name,
        permissionScope: data.permissionScope,
        fields: data.fields as Prisma.JsonArray,
        icon: data.icon,
      },
      include: {
        credentials: true,
      },
    });

    return new CredentialTypeController(credentialType);
  },

  /**
   * Delete Credential Type
   *
   * Delete a credential type by its ID.
   * This will cascade delete all credentials of this type.
   *
   * @param id - The credential type ID to delete
   * @returns {Promise<void>}
   */
  async delete(id: string): Promise<void> {
    await prisma.credentialType.delete({
      where: { id },
    });
  },
};
