/**
 * Repository pattern for Anvil server queries
 * Centralizes DB query logic to eliminate code duplication
 */

import type { D1Database } from '@cloudflare/workers-types';
import type { Server } from '../types';
import { buildFlexibleRegionConditionsAnvil, DEFAULT_ANVIL_REGION_FILTER_SQL } from '../region-utils';
import { isValidServer } from '../utils';

export interface ServerFilters {
  minCpu?: number;
  minMemoryGb?: number;
  region?: string[];
  budgetLimit?: number;
  limit?: number;
}

/**
 * Repository for Anvil server data access
 * Handles all queries to anvil_instances, anvil_pricing, anvil_regions, anvil_transfer_pricing
 */
export class AnvilServerRepository {
  constructor(private db: D1Database) {}

  /**
   * Find servers matching the given filters
   * Used by both /api/servers and /api/recommend endpoints
   */
  async findServers(filters: ServerFilters): Promise<Server[]> {
    const {
      minCpu,
      minMemoryGb,
      region,
      budgetLimit,
      limit = 100
    } = filters;

    // Build base query joining all Anvil tables
    let query = `
      SELECT
        ap.id,
        'Anvil' as provider_name,
        ai.name as instance_id,
        ai.display_name as instance_name,
        ai.vcpus as vcpu,
        CAST(ai.memory_gb * 1024 AS INTEGER) as memory_mb,
        ai.memory_gb,
        ai.disk_gb as storage_gb,
        ai.network_gbps as network_speed_gbps,
        ai.category as instance_family,
        CASE WHEN ai.gpu_model IS NOT NULL THEN 1 ELSE 0 END as gpu_count,
        ai.gpu_model as gpu_type,
        ap.monthly_price,
        ar.display_name as region_name,
        ar.name as region_code,
        ar.country_code,
        ai.transfer_tb,
        atp.price_per_gb as transfer_price_per_gb
      FROM anvil_instances ai
      JOIN anvil_pricing ap ON ap.anvil_instance_id = ai.id
      JOIN anvil_regions ar ON ap.anvil_region_id = ar.id
      LEFT JOIN anvil_transfer_pricing atp ON atp.anvil_region_id = ar.id
      WHERE ai.active = 1 AND ar.active = 1
    `;

    const params: (string | number)[] = [];

    // Apply default region filter if no specific region requested
    if (!region || region.length === 0) {
      query += ` AND ${DEFAULT_ANVIL_REGION_FILTER_SQL}`;
    }

    // Filter by minimum vCPU
    if (minCpu !== undefined && minCpu > 0) {
      query += ` AND ai.vcpus >= ?`;
      params.push(minCpu);
      console.log(`[AnvilServerRepository] Filtering by minimum vCPU: ${minCpu}`);
    }

    // Filter by minimum memory (input is in GB)
    if (minMemoryGb !== undefined && minMemoryGb > 0) {
      query += ` AND ai.memory_gb >= ?`;
      params.push(minMemoryGb);
      console.log(`[AnvilServerRepository] Filtering by minimum memory: ${(minMemoryGb * 1024).toFixed(0)}MB (${minMemoryGb.toFixed(1)}GB)`);
    }

    // Filter by region preference
    if (region && region.length > 0) {
      const { conditions, params: regionParams } = buildFlexibleRegionConditionsAnvil(region);
      if (conditions.length > 0) {
        query += ` AND (${conditions.join(' OR ')})`;
        params.push(...regionParams);
        console.log(`[AnvilServerRepository] Filtering by regions: ${region.join(', ')}`);
      }
    }

    // Filter by budget limit
    if (budgetLimit !== undefined && budgetLimit > 0) {
      query += ` AND ap.monthly_price <= ?`;
      params.push(budgetLimit);
    }

    // Order by price ascending and apply limit
    query += ` ORDER BY ap.monthly_price ASC LIMIT ?`;
    params.push(limit);

    // Execute query
    const result = await this.db.prepare(query).bind(...params).all();

    if (!result.success) {
      throw new Error('Database query failed for server search');
    }

    // Add currency field and validate results
    const serversWithCurrency = (result.results as unknown[]).map(server => {
      if (typeof server === 'object' && server !== null) {
        const s = server as Record<string, unknown>;
        return {
          ...s,
          monthly_price: s.monthly_price as number,
          currency: 'USD' as const,
          transfer_tb: s.transfer_tb as number | null,
          transfer_price_per_gb: s.transfer_price_per_gb as number | null
        };
      }
      return server;
    });

    const validServers = serversWithCurrency.filter(isValidServer);
    const invalidCount = result.results.length - validServers.length;

    if (invalidCount > 0) {
      console.warn(`[AnvilServerRepository] Filtered out ${invalidCount} invalid server records`);
    }

    console.log(`[AnvilServerRepository] Found ${validServers.length} servers matching filters`);

    return validServers;
  }

  /**
   * Find a single server by ID (pricing ID, unique per instance+region)
   */
  async findServerById(id: number): Promise<Server | null> {
    const query = `
      SELECT
        ap.id,
        'Anvil' as provider_name,
        ai.name as instance_id,
        ai.display_name as instance_name,
        ai.vcpus as vcpu,
        CAST(ai.memory_gb * 1024 AS INTEGER) as memory_mb,
        ai.memory_gb,
        ai.disk_gb as storage_gb,
        ai.network_gbps as network_speed_gbps,
        ai.category as instance_family,
        CASE WHEN ai.gpu_model IS NOT NULL THEN 1 ELSE 0 END as gpu_count,
        ai.gpu_model as gpu_type,
        ap.monthly_price,
        ar.display_name as region_name,
        ar.name as region_code,
        ar.country_code,
        ai.transfer_tb,
        atp.price_per_gb as transfer_price_per_gb
      FROM anvil_instances ai
      JOIN anvil_pricing ap ON ap.anvil_instance_id = ai.id
      JOIN anvil_regions ar ON ap.anvil_region_id = ar.id
      LEFT JOIN anvil_transfer_pricing atp ON atp.anvil_region_id = ar.id
      WHERE ap.id = ? AND ai.active = 1 AND ar.active = 1
    `;

    const result = await this.db.prepare(query).bind(id).first();

    if (!result) {
      return null;
    }

    const serverWithCurrency = {
      ...result,
      currency: 'USD' as const
    };

    return isValidServer(serverWithCurrency) ? serverWithCurrency : null;
  }
}
