import { z } from 'zod';

/**
 * Model preference configuration
 */
export const ModelPreferenceSchema = z.object({
  provider: z.enum(['anthropic', 'openai', 'google', 'openrouter']),
  model: z.string(),
  temperature: z.number().optional(),
});

export type ModelPreference = z.infer<typeof ModelPreferenceSchema>;

/**
 * Kubernetes resource allocations — stored per-user so they can be customized
 * beyond the standard tier defaults.
 */
export const K8sResourcesSchema = z.object({
  memoryRequest: z.string(),       // e.g. "256Mi"
  memoryLimit: z.string(),         // e.g. "512Mi"
  cpuRequest: z.string(),          // e.g. "100m"
  cpuLimit: z.string(),            // e.g. "500m"
  storage: z.string(),             // e.g. "1Gi"
  tmpSizeLimit: z.string(),        // e.g. "128Mi"
  enableIdleShutdown: z.boolean(),
  idleTimeoutMinutes: z.number(),
});

export type K8sResources = z.infer<typeof K8sResourcesSchema>;

/**
 * The portable License dict — stored as a single JSONB blob per user in the DB,
 * passable over-the-wire to any service that needs to enforce or inspect
 * feature access, resource limits, or preferences.
 *
 * Standard tier templates define the defaults; per-user rows are copies that
 * can be customised independently without schema changes.
 */
export const LicenseSchema = z.object({
  licenseType: z.enum(['free', 'pro', 'enterprise']),
  features: z.object({
    maxIndicators: z.number(),
    maxStrategies: z.number(),
    maxBacktestDays: z.number(),
    realtimeData: z.boolean(),
    customExecutors: z.boolean(),
    apiAccess: z.boolean(),
  }),
  resourceLimits: z.object({
    maxConcurrentSessions: z.number(),
    maxMessagesPerDay: z.number(),
    maxTokensPerMessage: z.number(),
    rateLimitPerMinute: z.number(),
  }),
  k8sResources: K8sResourcesSchema,
  preferredModel: ModelPreferenceSchema.optional(),
});

export type License = z.infer<typeof LicenseSchema>;
export type LicenseTier = License['licenseType'];

/**
 * Standard tier templates — single source of truth for default License values.
 * Used when creating new user accounts (copy the tier template into the user's
 * license row) and anywhere tier-specific defaults are needed.
 */
export const LICENSE_TIER_TEMPLATES: Record<LicenseTier, License> = {
  free: {
    licenseType: 'free',
    features: {
      maxIndicators: 5, maxStrategies: 3, maxBacktestDays: 30,
      realtimeData: false, customExecutors: false, apiAccess: false,
    },
    resourceLimits: {
      maxConcurrentSessions: 1, maxMessagesPerDay: 100,
      maxTokensPerMessage: 4096, rateLimitPerMinute: 10,
    },
    k8sResources: {
      memoryRequest: '256Mi', memoryLimit: '8Gi',
      cpuRequest: '100m',     cpuLimit: '500m',
      storage: '1Gi',         tmpSizeLimit: '128Mi',
      enableIdleShutdown: true, idleTimeoutMinutes: 15,
    },
  },
  pro: {
    licenseType: 'pro',
    features: {
      maxIndicators: 50, maxStrategies: 20, maxBacktestDays: 365,
      realtimeData: true, customExecutors: true, apiAccess: true,
    },
    resourceLimits: {
      maxConcurrentSessions: 5, maxMessagesPerDay: 1000,
      maxTokensPerMessage: 8192, rateLimitPerMinute: 60,
    },
    k8sResources: {
      memoryRequest: '512Mi', memoryLimit: '8Gi',
      cpuRequest: '250m',     cpuLimit: '2000m',
      storage: '10Gi',        tmpSizeLimit: '256Mi',
      enableIdleShutdown: false, idleTimeoutMinutes: 0,
    },
  },
  enterprise: {
    licenseType: 'enterprise',
    features: {
      maxIndicators: 999, maxStrategies: 999, maxBacktestDays: 3650,
      realtimeData: true, customExecutors: true, apiAccess: true,
    },
    resourceLimits: {
      maxConcurrentSessions: 20, maxMessagesPerDay: 10000,
      maxTokensPerMessage: 32768, rateLimitPerMinute: 300,
    },
    k8sResources: {
      memoryRequest: '1Gi',   memoryLimit: '8Gi',
      cpuRequest: '500m',     cpuLimit: '4000m',
      storage: '50Gi',        tmpSizeLimit: '512Mi',
      enableIdleShutdown: false, idleTimeoutMinutes: 0,
    },
  },
};

/**
 * UserLicense — DB row envelope. Wraps the portable License dict with account
 * identity and metadata. Not intended to be sent over-the-wire directly;
 * use the nested `license` field for cross-service communication.
 */
export const UserLicenseSchema = z.object({
  userId: z.string(),
  email: z.string().email().optional(),
  license: LicenseSchema,
  mcpServerUrl: z.string(), // Allow any string including 'pending'; validated at use time
  expiresAt: z.union([z.date(), z.string(), z.null()]).optional().transform(val => {
    if (!val || val === null) return undefined;
    return val instanceof Date ? val : new Date(val);
  }),
  createdAt: z.union([z.date(), z.string()]).transform(val =>
    val instanceof Date ? val : new Date(val)
  ),
  updatedAt: z.union([z.date(), z.string()]).transform(val =>
    val instanceof Date ? val : new Date(val)
  ),
});

export type UserLicense = z.infer<typeof UserLicenseSchema>;

/**
 * Channel types for multi-channel support
 */
export enum ChannelType {
  WEBSOCKET = 'websocket',
  TELEGRAM = 'telegram',
  SLACK = 'slack',
  DISCORD = 'discord',
}

/**
 * Authentication context per channel session.
 * `license` is the portable License dict (not the full UserLicense row).
 * `mcpServerUrl` is the runtime container endpoint, resolved at auth time.
 */
export const AuthContextSchema = z.object({
  userId: z.string(),
  channelType: z.nativeEnum(ChannelType),
  channelUserId: z.string(), // Platform-specific ID (telegram_id, discord_id, etc)
  sessionId: z.string(),
  license: LicenseSchema,
  mcpServerUrl: z.string(),
  authenticatedAt: z.date(),
});

export type AuthContext = z.infer<typeof AuthContextSchema>;
