import {
  type ImageGenerationProvider,
  type ImageProviderCredentials,
  type TextToImageParams,
  type ImageToImageParams,
  type ImageGenerationResult,
  ImageGenerationError,
  registerImageProvider,
} from './types.js';

interface MiniMaxResponse {
  id?: string;
  data?: { image_urls?: string[]; image_base64?: string[] };
  metadata?: { success_count?: number; failed_count?: number };
  base_resp?: { status_code?: number; status_msg?: string };
}

function buildBaseBody(params: TextToImageParams, creds: ImageProviderCredentials): Record<string, unknown> {
  const body: Record<string, unknown> = {
    model: creds.modelId,
    prompt: params.prompt,
    n: params.n ?? 1,
    response_format: params.responseFormat ?? 'url',
  };
  if (params.watermark !== undefined) body.aigc_watermark = params.watermark;
  if (params.aspectRatio) {
    body.aspect_ratio = params.aspectRatio;
  } else if (params.width && params.height) {
    body.width = params.width;
    body.height = params.height;
  }
  if (params.seed !== undefined) body.seed = params.seed;
  if (params.extra?.style) body.style = params.extra.style;
  if (params.extra?.prompt_optimizer !== undefined) body.prompt_optimizer = params.extra.prompt_optimizer;
  return body;
}

function normalizeResponse(json: MiniMaxResponse, creds: ImageProviderCredentials, format: string): ImageGenerationResult {
  const resp = json.base_resp;
  if (resp && resp.status_code !== 0) {
    const code = resp.status_code;
    if (code === 1026) throw new ImageGenerationError('提示词触发内容安全策略，请调整描述', 'content_safety', false);
    if (code === 1002) throw new ImageGenerationError('当前请求过多，请稍后重试', 'rate_limit', true);
    if (code === 1008) throw new ImageGenerationError('模型渠道余额不足', 'insufficient_balance', false);
    if (code === 1004) throw new ImageGenerationError('API Key 鉴权失败', 'invalid_params', false);
    throw new ImageGenerationError(resp.status_msg ?? `MiniMax error ${code}`, 'unknown', false);
  }
  const urls = json.data?.image_urls ?? [];
  const b64s = json.data?.image_base64 ?? [];
  const images = format === 'base64'
    ? b64s.map(b => ({ base64: b }))
    : urls.map(u => ({ url: u }));
  return { images, model: creds.modelId, provider: 'minimax' };
}

class MiniMaxImageProvider implements ImageGenerationProvider {
  readonly id = 'minimax';

  async textToImage(params: TextToImageParams, creds: ImageProviderCredentials): Promise<ImageGenerationResult> {
    const body = buildBaseBody(params, creds);
    return this.request(body, creds, params.responseFormat ?? 'url');
  }

  async imageToImage(params: ImageToImageParams, creds: ImageProviderCredentials): Promise<ImageGenerationResult> {
    const body = buildBaseBody(params, creds);
    body.subject_reference = [{ image: params.referenceImage }];
    if (params.strength !== undefined) body.strength = params.strength;
    return this.request(body, creds, params.responseFormat ?? 'url');
  }

  private async request(body: Record<string, unknown>, creds: ImageProviderCredentials, format: string): Promise<ImageGenerationResult> {
    const controller = new AbortController();
    const timer = setTimeout(() => controller.abort(), 60_000);
    try {
      const baseUrl = creds.baseUrl.replace(/\/+$/, '');
      const res = await fetch(`${baseUrl}/image_generation`, {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
          'Authorization': `Bearer ${creds.apiKey}`,
        },
        body: JSON.stringify(body),
        signal: controller.signal,
      });
      if (!res.ok) {
        const text = await res.text().catch(() => '');
        throw new ImageGenerationError(`MiniMax HTTP ${res.status}: ${text}`, res.status === 429 ? 'rate_limit' : 'unknown', res.status === 429);
      }
      const json: MiniMaxResponse = await res.json();
      return normalizeResponse(json, creds, format);
    } catch (err: any) {
      if (err instanceof ImageGenerationError) throw err;
      if (err?.name === 'AbortError') throw new ImageGenerationError('生成超时，可尝试降低图片尺寸', 'timeout', true);
      throw new ImageGenerationError(err?.message ?? String(err), 'network', true);
    } finally {
      clearTimeout(timer);
    }
  }
}

registerImageProvider(new MiniMaxImageProvider());
