import { Inject, Injectable, Logger, type OnModuleInit } from '@nestjs/common';
import { routingRules, type Db, sql } from '@mosaicstack/db';
import { DB } from '../../database/database.module.js';
import type { RoutingCondition, RoutingAction } from './routing.types.js';

/** Seed-time routing rule descriptor */
interface RoutingRuleSeed {
  name: string;
  priority: number;
  conditions: RoutingCondition[];
  action: RoutingAction;
}

export const DEFAULT_ROUTING_RULES: RoutingRuleSeed[] = [
  {
    name: 'Complex coding → Opus',
    priority: 1,
    conditions: [
      { field: 'taskType', operator: 'eq', value: 'coding' },
      { field: 'complexity', operator: 'eq', value: 'complex' },
    ],
    action: { provider: 'anthropic', model: 'claude-opus-4-6' },
  },
  {
    name: 'Moderate coding → Sonnet',
    priority: 2,
    conditions: [
      { field: 'taskType', operator: 'eq', value: 'coding' },
      { field: 'complexity', operator: 'eq', value: 'moderate' },
    ],
    action: { provider: 'anthropic', model: 'claude-sonnet-4-6' },
  },
  {
    name: 'Simple coding → Codex',
    priority: 3,
    conditions: [
      { field: 'taskType', operator: 'eq', value: 'coding' },
      { field: 'complexity', operator: 'eq', value: 'simple' },
    ],
    action: { provider: 'openai', model: 'codex-gpt-5-4' },
  },
  {
    name: 'Research → Codex',
    priority: 4,
    conditions: [{ field: 'taskType', operator: 'eq', value: 'research' }],
    action: { provider: 'openai', model: 'codex-gpt-5-4' },
  },
  {
    name: 'Summarization → GLM-5',
    priority: 5,
    conditions: [{ field: 'taskType', operator: 'eq', value: 'summarization' }],
    action: { provider: 'zai', model: 'glm-5' },
  },
  {
    name: 'Analysis with reasoning → Opus',
    priority: 6,
    conditions: [
      { field: 'taskType', operator: 'eq', value: 'analysis' },
      { field: 'requiredCapabilities', operator: 'includes', value: 'reasoning' },
    ],
    action: { provider: 'anthropic', model: 'claude-opus-4-6' },
  },
  {
    name: 'Conversation → Sonnet',
    priority: 7,
    conditions: [{ field: 'taskType', operator: 'eq', value: 'conversation' }],
    action: { provider: 'anthropic', model: 'claude-sonnet-4-6' },
  },
  {
    name: 'Creative → Sonnet',
    priority: 8,
    conditions: [{ field: 'taskType', operator: 'eq', value: 'creative' }],
    action: { provider: 'anthropic', model: 'claude-sonnet-4-6' },
  },
  {
    name: 'Cheap/general → Haiku',
    priority: 9,
    conditions: [{ field: 'costTier', operator: 'eq', value: 'cheap' }],
    action: { provider: 'anthropic', model: 'claude-haiku-4-5' },
  },
  {
    name: 'Fallback → Sonnet',
    priority: 10,
    conditions: [],
    action: { provider: 'anthropic', model: 'claude-sonnet-4-6' },
  },
  {
    name: 'Offline → Ollama',
    priority: 99,
    conditions: [{ field: 'costTier', operator: 'eq', value: 'local' }],
    action: { provider: 'ollama', model: 'llama3.2' },
  },
];

@Injectable()
export class DefaultRoutingRulesSeed implements OnModuleInit {
  private readonly logger = new Logger(DefaultRoutingRulesSeed.name);

  constructor(@Inject(DB) private readonly db: Db) {}

  async onModuleInit(): Promise<void> {
    await this.seedDefaultRules();
  }

  /**
   * Insert default routing rules into the database if the table is empty.
   * Skips seeding if any system-scoped rules already exist.
   */
  async seedDefaultRules(): Promise<void> {
    const rows = await this.db
      .select({ count: sql<number>`count(*)::int` })
      .from(routingRules)
      .where(sql`scope = 'system'`);

    const count = rows[0]?.count ?? 0;
    if (count > 0) {
      this.logger.debug(
        `Skipping default routing rules seed — ${count} system rule(s) already exist`,
      );
      return;
    }

    this.logger.log(`Seeding ${DEFAULT_ROUTING_RULES.length} default routing rules`);

    await this.db.insert(routingRules).values(
      DEFAULT_ROUTING_RULES.map((rule) => ({
        name: rule.name,
        priority: rule.priority,
        scope: 'system' as const,
        conditions: rule.conditions as unknown as Record<string, unknown>[],
        action: rule.action as unknown as Record<string, unknown>,
        enabled: true,
      })),
    );

    this.logger.log('Default routing rules seeded successfully');
  }
}
