import { Injectable, Logger } from '@nestjs/common';
import { Cron, CronExpression } from '@nestjs/schedule';
import * as fs from 'fs';
import * as path from 'path';
import axios from 'axios';

export interface PricingEntry {
  id: string;
  tool: string;
  inputUsdPerMTok: string;
  outputUsdPerMTok: string;
  cacheCreationUsdPerMTok: string;
  cacheReadUsdPerMTok: string;
  inputUsdPerMTokAbove200k?: string;
  outputUsdPerMTokAbove200k?: string;
  cacheCreationUsdPerMTokAbove200k?: string;
  cacheReadUsdPerMTokAbove200k?: string;
}

export interface PricingTable {
  version: string;
  tierThresholdTokens?: number;
  models: PricingEntry[];
  source?: 'static' | 'litellm';
}

const LITELLM_URL =
  'https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json';

@Injectable()
export class AiUsagePricingService {
  private readonly logger = new Logger(AiUsagePricingService.name);
  private cached: PricingTable | null = null;

  load(): PricingTable {
    if (this.cached) return this.cached;
    return this.loadStatic();
  }

  getVersion(): string {
    return this.load().version;
  }

  /**
   * 每周一 02:00 UTC 从 LiteLLM 拉最新价目表合并。
   * 失败不抛错（静态价目表 fallback），写 warn log。
   */
  @Cron('0 2 * * 1', { timeZone: 'UTC' })
  async refreshFromLiteLLM() {
    try {
      const resp = await axios.get(LITELLM_URL, { timeout: 15_000 });
      const merged = this.mergeLiteLLM(resp.data, this.loadStatic());
      this.cached = merged;
      this.logger.log(`Pricing refreshed from LiteLLM (${merged.models.length} models, version ${merged.version})`);
    } catch (err: any) {
      this.logger.warn(`LiteLLM refresh failed (${err.message}); keeping static pricing`);
    }
  }

  private loadStatic(): PricingTable {
    const file = path.resolve(__dirname, '../pricing/pricing.json');
    const raw = fs.readFileSync(file, 'utf8');
    const t = JSON.parse(raw) as PricingTable;
    t.source = 'static';
    this.cached = t;
    this.logger.log(`Loaded static pricing v${t.version} (${t.models.length} models)`);
    return t;
  }

  /**
   * LiteLLM 格式 → 我们的格式。
   * LiteLLM keys 是 model id（如 `claude-opus-4-7-20260101`），值含
   * `input_cost_per_token` / `output_cost_per_token` / `cache_creation_input_token_cost`
   * / `cache_read_input_token_cost`（unit: USD/token）。我们存 USD/M token。
   */
  private mergeLiteLLM(litellm: Record<string, any>, baseline: PricingTable): PricingTable {
    const models: PricingEntry[] = [];
    for (const baseModel of baseline.models) {
      const llEntry = litellm[baseModel.id];
      if (!llEntry) {
        models.push(baseModel); // 保留静态
        continue;
      }
      const toM = (perToken: any) => (perToken ? (Number(perToken) * 1e6).toFixed(6) : undefined);
      models.push({
        id: baseModel.id,
        tool: baseModel.tool,
        inputUsdPerMTok: toM(llEntry.input_cost_per_token) ?? baseModel.inputUsdPerMTok,
        outputUsdPerMTok: toM(llEntry.output_cost_per_token) ?? baseModel.outputUsdPerMTok,
        cacheCreationUsdPerMTok:
          toM(llEntry.cache_creation_input_token_cost) ?? baseModel.cacheCreationUsdPerMTok,
        cacheReadUsdPerMTok:
          toM(llEntry.cache_read_input_token_cost) ?? baseModel.cacheReadUsdPerMTok,
        inputUsdPerMTokAbove200k:
          toM(llEntry.input_cost_per_token_above_200k_tokens) ?? baseModel.inputUsdPerMTokAbove200k,
        outputUsdPerMTokAbove200k:
          toM(llEntry.output_cost_per_token_above_200k_tokens) ?? baseModel.outputUsdPerMTokAbove200k,
        cacheCreationUsdPerMTokAbove200k:
          toM(llEntry.cache_creation_input_token_cost_above_200k_tokens) ??
          baseModel.cacheCreationUsdPerMTokAbove200k,
        cacheReadUsdPerMTokAbove200k:
          toM(llEntry.cache_read_input_token_cost_above_200k_tokens) ??
          baseModel.cacheReadUsdPerMTokAbove200k,
      });
    }
    return {
      version: new Date().toISOString().slice(0, 10),
      tierThresholdTokens: baseline.tierThresholdTokens ?? 200_000,
      models,
      source: 'litellm',
    };
  }
}
