import type { MediaCircuitState } from '../types';

const KIEAI_API_KEY = process.env.KIEAI_API_KEY || '';
const KIEAI_BASE = 'https://api.kie.ai/api/v1';
const MEDIA_ENABLED = process.env.TWITTER_MEDIA_ENABLED !== 'false';
const FAIL_THRESHOLD = parseInt(process.env.TWITTER_MEDIA_FAIL_THRESHOLD || '5');

// Circuit breaker state
const circuitState: MediaCircuitState = {
  consecutiveFailures: 0,
  disabledUntil: null,
};

export function isMediaAvailable(): boolean {
  if (!MEDIA_ENABLED) return false;
  if (!KIEAI_API_KEY) return false;
  if (circuitState.disabledUntil && circuitState.disabledUntil > new Date()) {
    return false;
  }
  // Reset if past disabled window
  if (circuitState.disabledUntil && circuitState.disabledUntil <= new Date()) {
    circuitState.disabledUntil = null;
    circuitState.consecutiveFailures = 0;
  }
  return true;
}

function recordSuccess(): void {
  circuitState.consecutiveFailures = 0;
}

function recordFailure(): void {
  circuitState.consecutiveFailures++;
  if (circuitState.consecutiveFailures >= FAIL_THRESHOLD) {
    circuitState.disabledUntil = new Date(Date.now() + 24 * 60 * 60 * 1000);
    console.error(`[kie-ai] CIRCUIT BREAKER: ${circuitState.consecutiveFailures} consecutive failures — media disabled until ${circuitState.disabledUntil.toISOString()}`);
  }
}

// ── Image Generation (Kie.ai GPT-4o Image / GPT-Image-1) ───

export async function generateImage(
  prompt: string,
  size: '1:1' | '3:2' | '2:3' = '2:3'
): Promise<{ taskId: string }> {
  const response = await fetch(`${KIEAI_BASE}/gpt4o-image/generate`, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      Authorization: `Bearer ${KIEAI_API_KEY}`,
    },
    body: JSON.stringify({
      prompt,
      size,
    }),
    signal: AbortSignal.timeout(30000),
  });

  if (!response.ok) {
    const errText = await response.text();
    throw new Error(`Kie.ai image generate failed ${response.status}: ${errText}`);
  }

  const data: any = await response.json();
  const taskId = data.data?.taskId || data.taskId || data.task_id || data.id;
  if (!taskId) throw new Error(`Kie.ai image generate: no taskId in response: ${JSON.stringify(data).slice(0, 200)}`);
  return { taskId };
}

// ── Video Generation (Kie.ai Runway Gen-4 Turbo) ───────────

export async function generateVideo(
  prompt: string
): Promise<{ taskId: string }> {
  const response = await fetch(`${KIEAI_BASE}/runway/generate`, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      Authorization: `Bearer ${KIEAI_API_KEY}`,
    },
    body: JSON.stringify({
      prompt,
      aspectRatio: '9:16',
      duration: 5,
      quality: '720p',
    }),
    signal: AbortSignal.timeout(30000),
  });

  if (!response.ok) {
    const errText = await response.text();
    throw new Error(`Kie.ai video generate failed ${response.status}: ${errText}`);
  }

  const data: any = await response.json();
  const taskId = data.data?.taskId || data.taskId || data.task_id || data.id;
  if (!taskId) throw new Error(`Kie.ai video generate: no taskId in response: ${JSON.stringify(data).slice(0, 200)}`);
  return { taskId };
}

// ── Poll for Image Result ───────────────────────────────────

async function waitForImage(taskId: string, maxWaitMs: number = 120000): Promise<string> {
  const pollInterval = 10000; // docs recommend 10s for images
  const start = Date.now();

  while (Date.now() - start < maxWaitMs) {
    const res = await fetch(
      `${KIEAI_BASE}/gpt4o-image/record-info?taskId=${encodeURIComponent(taskId)}`,
      {
        headers: { Authorization: `Bearer ${KIEAI_API_KEY}` },
        signal: AbortSignal.timeout(15000),
      }
    );

    if (!res.ok) {
      const errText = await res.text();
      console.warn(`[kie-ai] Image status poll failed ${res.status}: ${errText}`);
      await new Promise((r) => setTimeout(r, pollInterval));
      continue;
    }

    const json: any = await res.json();
    const data = json.data || json;

    // successFlag: 0 = in progress, 1 = success, 2 = failed
    if (data.successFlag === 1 || data.status === 'SUCCESS') {
      const urls = data.response?.resultUrls;
      const url = Array.isArray(urls) && urls.length > 0 ? urls[0] : null;
      if (!url) throw new Error(`Kie.ai image completed but no resultUrls: ${JSON.stringify(data).slice(0, 300)}`);
      recordSuccess();
      return url;
    }

    if (data.successFlag === 2 || data.status === 'CREATE_TASK_FAILED' || data.status === 'GENERATE_FAILED') {
      recordFailure();
      throw new Error(`Kie.ai image task ${taskId} failed: ${data.errorMessage || data.errorCode || 'unknown'}`);
    }

    // Still generating
    await new Promise((r) => setTimeout(r, pollInterval));
  }

  recordFailure();
  throw new Error(`Kie.ai image task ${taskId} timed out after ${maxWaitMs}ms`);
}

// ── Poll for Video Result ───────────────────────────────────

async function waitForVideo(taskId: string, maxWaitMs: number = 300000): Promise<string> {
  const pollInterval = 30000; // docs recommend 30s for video
  const start = Date.now();

  while (Date.now() - start < maxWaitMs) {
    const res = await fetch(
      `${KIEAI_BASE}/runway/record-detail?taskId=${encodeURIComponent(taskId)}`,
      {
        headers: { Authorization: `Bearer ${KIEAI_API_KEY}` },
        signal: AbortSignal.timeout(15000),
      }
    );

    if (!res.ok) {
      const errText = await res.text();
      console.warn(`[kie-ai] Video status poll failed ${res.status}: ${errText}`);
      await new Promise((r) => setTimeout(r, pollInterval));
      continue;
    }

    const json: any = await res.json();
    const data = json.data || json;

    // state: wait, queueing, generating, success, fail
    if (data.state === 'success') {
      const url = data.videoInfo?.videoUrl;
      if (!url) throw new Error(`Kie.ai video completed but no videoUrl: ${JSON.stringify(data).slice(0, 300)}`);
      recordSuccess();
      return url;
    }

    if (data.state === 'fail') {
      recordFailure();
      throw new Error(`Kie.ai video task ${taskId} failed: ${data.failMsg || 'unknown'}`);
    }

    // Still processing (wait/queueing/generating)
    await new Promise((r) => setTimeout(r, pollInterval));
  }

  recordFailure();
  throw new Error(`Kie.ai video task ${taskId} timed out after ${maxWaitMs}ms`);
}

// ── Download Media to Buffer ────────────────────────────────

export async function downloadMedia(url: string): Promise<Buffer> {
  const response = await fetch(url, { signal: AbortSignal.timeout(60000) });
  if (!response.ok) {
    throw new Error(`Failed to download media from ${url}: ${response.status}`);
  }
  const arrayBuffer = await response.arrayBuffer();
  return Buffer.from(arrayBuffer);
}

// ── Full Pipeline: Generate → Wait → Download ───────────────

export async function generateAndDownloadImage(prompt: string): Promise<{ buffer: Buffer; mimeType: string } | null> {
  if (!isMediaAvailable()) return null;

  try {
    console.log(`[kie-ai] Generating portrait image: "${prompt.substring(0, 60)}..."`);
    const { taskId } = await generateImage(prompt, '2:3');
    console.log(`[kie-ai] Image task ${taskId} — polling...`);
    const url = await waitForImage(taskId);
    console.log(`[kie-ai] Image ready: ${url}`);
    const buffer = await downloadMedia(url);
    return { buffer, mimeType: 'image/png' };
  } catch (err) {
    console.error(`[kie-ai] Image pipeline failed:`, (err as Error).message);
    recordFailure();
    return null;
  }
}

export async function generateAndDownloadVideo(prompt: string): Promise<{ buffer: Buffer; mimeType: string } | null> {
  if (!isMediaAvailable()) return null;

  try {
    console.log(`[kie-ai] Generating portrait video (9:16): "${prompt.substring(0, 60)}..."`);
    const { taskId } = await generateVideo(prompt);
    console.log(`[kie-ai] Video task ${taskId} — polling...`);
    const url = await waitForVideo(taskId);
    console.log(`[kie-ai] Video ready: ${url}`);
    const buffer = await downloadMedia(url);
    return { buffer, mimeType: 'video/mp4' };
  } catch (err) {
    console.error(`[kie-ai] Video pipeline failed:`, (err as Error).message);
    recordFailure();
    return null;
  }
}

export function getCircuitState(): MediaCircuitState {
  return { ...circuitState };
}
