import { LOCAL_MCP_INSTALLATION_STATES } from "@archestra/shared";
import {
  createInsertSchema,
  createSelectSchema,
  createUpdateSchema,
} from "drizzle-zod";
import { z } from "zod";
import { schema } from "@/database";
import { InternalMcpCatalogServerTypeSchema } from "./mcp-catalog";
import { ResourceVisibilityScopeSchema } from "./visibility";

export const LocalMcpServerInstallationStatusSchema = z.enum(
  LOCAL_MCP_INSTALLATION_STATES,
);

export const SecretStorageTypeSchema = z.enum([
  "vault",
  "external_vault",
  "database",
  "none",
]);

export type SecretStorageType = z.infer<typeof SecretStorageTypeSchema>;

export const SelectMcpServerSchema = createSelectSchema(
  schema.mcpServersTable,
).extend({
  serverType: InternalMcpCatalogServerTypeSchema,
  scope: ResourceVisibilityScopeSchema,
  ownerEmail: z.string().nullable().optional(),
  catalogName: z.string().nullable().optional(),
  users: z.array(z.string()).optional(),
  userDetails: z
    .array(
      z.object({
        userId: z.string(),
        email: z.string(),
        createdAt: z.coerce.date(),
      }),
    )
    .optional(),
  teamDetails: z
    .object({
      teamId: z.string(),
      name: z.string(),
      createdAt: z.coerce.date(),
    })
    .nullable()
    .optional(),
  localInstallationStatus: LocalMcpServerInstallationStatusSchema,
  secretStorageType: SecretStorageTypeSchema.optional(),
});

export const InsertMcpServerSchema = createInsertSchema(schema.mcpServersTable)
  .extend({
    serverType: InternalMcpCatalogServerTypeSchema,
    scope: ResourceVisibilityScopeSchema.optional(),
    userId: z.string().optional(), // For personal auth
    localInstallationStatus: LocalMcpServerInstallationStatusSchema.optional(),
    userConfigValues: z.record(z.string(), z.string()).optional(),
    environmentValues: z.record(z.string(), z.string()).optional(),
  })
  .omit({
    id: true,
    createdAt: true,
    updatedAt: true,
    // Server-owned OAuth refresh-failure state, written only by the refresh
    // subsystem (routes/oauth.ts) — a freshly installed server has never
    // attempted a refresh, and accepting these from install input would let
    // a caller seed arbitrary (including unsanitized) diagnostic text shown
    // to other users with access to the install.
    oauthRefreshError: true,
    oauthRefreshErrorMessage: true,
    oauthRefreshErrorDescription: true,
    oauthRefreshFailedAt: true,
  });

export const UpdateMcpServerSchema = createUpdateSchema(schema.mcpServersTable)
  .omit({
    serverType: true, // serverType should not be updated after creation
    scope: true, // scope is install-time only; to change scope, uninstall + reinstall
  })
  .extend({
    localInstallationStatus: LocalMcpServerInstallationStatusSchema.optional(),
  });

export type LocalMcpServerInstallationStatus = z.infer<
  typeof LocalMcpServerInstallationStatusSchema
>;

export type McpServer = z.infer<typeof SelectMcpServerSchema>;
export type InsertMcpServer = z.infer<typeof InsertMcpServerSchema>;
export type UpdateMcpServer = z.infer<typeof UpdateMcpServerSchema>;
