import { Injectable, Logger, BadRequestException, NotFoundException } from '@nestjs/common';
import { promises as fs } from 'fs';
import { join } from 'path';
import type {
  AiConfigPublic,
  AiConfigStored,
  AiProviderConfig,
  AiProviderPublic,
  AiProviderUpsertInput,
} from '@ftb/shared';

const CONFIG_FILE = join(process.cwd(), 'data', 'ai-config.json');

const DEFAULT_MODEL = 'claude-sonnet-4-6';

@Injectable()
export class AiConfigService {
  private readonly logger = new Logger(AiConfigService.name);
  private cache: AiConfigStored | null = null;

  /**
   * 当前激活的提供商配置（含完整 apiKey），用于 AiGateway 实例化客户端
   */
  async getActiveProvider(): Promise<AiProviderConfig | null> {
    const cfg = await this.read();
    if (!cfg.activeProviderId) {
      // 兜底：环境变量
      const envKey = process.env.ANTHROPIC_API_KEY;
      if (envKey) {
        return {
          id: '__env__',
          name: '环境变量',
          format: 'anthropic',
          baseURL: 'https://api.anthropic.com',
          apiKey: envKey,
          model: DEFAULT_MODEL,
          createdAt: new Date(0).toISOString(),
        };
      }
      return null;
    }
    return cfg.providers.find((p) => p.id === cfg.activeProviderId) ?? null;
  }

  /**
   * 前端用的整体视图
   */
  async getPublic(): Promise<AiConfigPublic> {
    const cfg = await this.read();
    return {
      providers: cfg.providers.map((p) => this.toPublic(p, p.id === cfg.activeProviderId)),
      activeProviderId: cfg.activeProviderId,
      updatedAt: cfg.updatedAt,
      updatedBy: cfg.updatedBy,
    };
  }

  /**
   * 创建或更新提供商
   * 若 input.apiKey 为空且 id 已存在，则保留原 key
   */
  async upsertProvider(input: AiProviderUpsertInput, operator?: string): Promise<AiConfigPublic> {
    if (!input.id) throw new BadRequestException('id 必填');
    if (!input.name) throw new BadRequestException('name 必填');
    if (!input.baseURL) throw new BadRequestException('baseURL 必填');
    if (!input.model) throw new BadRequestException('model 必填');

    const cfg = await this.read();
    const existingIdx = cfg.providers.findIndex((p) => p.id === input.id);

    const apiKey = input.apiKey || cfg.providers[existingIdx]?.apiKey;
    if (!apiKey) throw new BadRequestException('apiKey 必填');

    const provider: AiProviderConfig = {
      id: input.id,
      name: input.name,
      format: input.format,
      baseURL: input.baseURL,
      apiKey,
      model: input.model,
      remark: input.remark,
      createdAt:
        existingIdx >= 0 ? cfg.providers[existingIdx].createdAt : new Date().toISOString(),
    };

    if (existingIdx >= 0) {
      cfg.providers[existingIdx] = provider;
    } else {
      cfg.providers.push(provider);
      // 第一个新增的自动激活
      if (!cfg.activeProviderId) cfg.activeProviderId = provider.id;
    }

    cfg.updatedAt = new Date().toISOString();
    cfg.updatedBy = operator;
    await this.write(cfg);
    return this.getPublic();
  }

  async deleteProvider(id: string, operator?: string): Promise<AiConfigPublic> {
    const cfg = await this.read();
    const idx = cfg.providers.findIndex((p) => p.id === id);
    if (idx < 0) throw new NotFoundException('提供商不存在');
    cfg.providers.splice(idx, 1);
    if (cfg.activeProviderId === id) {
      cfg.activeProviderId = cfg.providers[0]?.id;
    }
    cfg.updatedAt = new Date().toISOString();
    cfg.updatedBy = operator;
    await this.write(cfg);
    return this.getPublic();
  }

  async activate(id: string, operator?: string): Promise<AiConfigPublic> {
    const cfg = await this.read();
    if (!cfg.providers.find((p) => p.id === id)) {
      throw new NotFoundException('提供商不存在');
    }
    cfg.activeProviderId = id;
    cfg.updatedAt = new Date().toISOString();
    cfg.updatedBy = operator;
    await this.write(cfg);
    return this.getPublic();
  }

  /**
   * 取某个提供商的完整配置（含 apiKey），仅供同进程内的服务调用（如 ping/decompose）
   */
  async getProviderFullById(id: string): Promise<AiProviderConfig | null> {
    const cfg = await this.read();
    return cfg.providers.find((p) => p.id === id) ?? null;
  }

  private async read(): Promise<AiConfigStored> {
    if (this.cache) return this.cache;
    try {
      const buf = await fs.readFile(CONFIG_FILE, 'utf-8');
      const parsed = JSON.parse(buf);
      this.cache = this.migrate(parsed);
      return this.cache!;
    } catch (e: any) {
      if (e.code !== 'ENOENT') this.logger.warn(`读取 ai-config.json 失败: ${e.message}`);
      this.cache = { providers: [] };
      return this.cache;
    }
  }

  /**
   * 旧数据格式（单 apiKey + model）迁移到新格式（providers[]）
   */
  private migrate(raw: any): AiConfigStored {
    if (Array.isArray(raw?.providers)) return raw as AiConfigStored;
    // 旧格式：{ anthropicApiKey, model, updatedAt, updatedBy }
    if (raw?.anthropicApiKey) {
      this.logger.log('检测到旧版 ai-config.json，自动迁移为多 provider 结构');
      const legacy: AiProviderConfig = {
        id: 'anthropic-official',
        name: 'Anthropic 官方',
        format: 'anthropic',
        baseURL: 'https://api.anthropic.com',
        apiKey: raw.anthropicApiKey,
        model: raw.model || DEFAULT_MODEL,
        createdAt: raw.updatedAt || new Date().toISOString(),
      };
      return {
        providers: [legacy],
        activeProviderId: legacy.id,
        updatedAt: raw.updatedAt,
        updatedBy: raw.updatedBy,
      };
    }
    return { providers: [] };
  }

  private async write(data: AiConfigStored): Promise<void> {
    await fs.mkdir(join(process.cwd(), 'data'), { recursive: true });
    await fs.writeFile(CONFIG_FILE, JSON.stringify(data, null, 2), 'utf-8');
    this.cache = data;
  }

  private toPublic(p: AiProviderConfig, isActive: boolean): AiProviderPublic {
    return {
      id: p.id,
      name: p.name,
      format: p.format,
      baseURL: p.baseURL,
      keyMask: this.mask(p.apiKey),
      model: p.model,
      remark: p.remark,
      createdAt: p.createdAt,
      isActive,
    };
  }

  private mask(key: string): string {
    if (!key) return '';
    if (key.length <= 10) return '****';
    return `${key.slice(0, 6)}...${key.slice(-4)}`;
  }
}
