export const dynamic = 'force-dynamic'
export const runtime = 'nodejs'

import { NextResponse } from 'next/server'
import * as https from 'node:https'
import { Readable } from 'node:stream'
import { HttpsProxyAgent } from 'https-proxy-agent'

const ELEVENLABS_HOST = 'api.elevenlabs.io'
const DEFAULT_MODEL = 'eleven_flash_v2_5'

// ElevenLabs blocks Russian IPs at Cloudflare level; route via non-RU proxy
// (set ELEVENLABS_PROXY=http://192.168.31.103:8888 in tablet.env).
// Falls back to HTTPS_PROXY / HTTP_PROXY if set.
function getProxyAgent(): HttpsProxyAgent<string> | null {
  const proxy =
    process.env.ELEVENLABS_PROXY ||
    process.env.HTTPS_PROXY ||
    process.env.HTTP_PROXY ||
    ''
  return proxy ? new HttpsProxyAgent(proxy) : null
}

function getVoiceId(agent: string | undefined): string | null {
  if (agent === 'lusya') return process.env.LUSYA_TTS_VOICE || null
  return process.env.COSMO_TTS_VOICE || null
}

interface UpstreamResult {
  status: number
  body: Readable | null
  error?: string
}

function requestElevenLabs(voiceId: string, payload: string, apiKey: string): Promise<UpstreamResult> {
  return new Promise((resolve) => {
    const options: https.RequestOptions = {
      host: ELEVENLABS_HOST,
      path: `/v1/text-to-speech/${encodeURIComponent(voiceId)}/stream?output_format=mp3_44100_64`,
      method: 'POST',
      headers: {
        'xi-api-key': apiKey,
        Accept: 'audio/mpeg',
        'Content-Type': 'application/json',
        'Content-Length': Buffer.byteLength(payload).toString(),
      },
      timeout: 30000,
    }
    const proxyAgent = getProxyAgent()
    if (proxyAgent) options.agent = proxyAgent

    const req = https.request(options, (res) => {
      if ((res.statusCode || 0) !== 200) {
        let errText = ''
        res.setEncoding('utf8')
        res.on('data', (chunk: string) => { errText += chunk })
        res.on('end', () =>
          resolve({ status: res.statusCode || 0, body: null, error: errText.slice(0, 500) })
        )
        return
      }
      resolve({ status: 200, body: res })
    })

    req.on('timeout', () => req.destroy(new Error('elevenlabs_timeout')))
    req.on('error', (e) => resolve({ status: 0, body: null, error: e.message }))

    req.write(payload)
    req.end()
  })
}

export async function POST(req: Request) {
  const apiKey = process.env.ELEVENLABS_API_KEY
  if (!apiKey) {
    return NextResponse.json({ error: 'tts_not_configured' }, { status: 503 })
  }

  const body = await req.json().catch(() => null)
  const text = typeof body?.text === 'string' ? body.text.trim() : ''
  const agent = typeof body?.agent === 'string' ? body.agent : 'cosmo'

  if (!text) {
    return NextResponse.json({ error: 'text required' }, { status: 400 })
  }
  if (text.length > 4000) {
    return NextResponse.json({ error: 'text too long (>4000)' }, { status: 400 })
  }

  const voiceId = getVoiceId(agent)
  if (!voiceId) {
    return NextResponse.json({ error: `no voice configured for agent=${agent}` }, { status: 503 })
  }

  const model = process.env.ELEVENLABS_MODEL || DEFAULT_MODEL

  const payload = JSON.stringify({
    text,
    model_id: model,
    voice_settings: {
      stability: 0.45,
      similarity_boost: 0.75,
      style: 0.25,
      use_speaker_boost: true,
    },
  })

  const result = await requestElevenLabs(voiceId, payload, apiKey)

  if (result.status !== 200 || !result.body) {
    return NextResponse.json(
      { error: `elevenlabs_${result.status || 'fetch_failed'}`, detail: result.error || '' },
      { status: 502 }
    )
  }

  // Node Readable -> Web ReadableStream for Next.js Response
  const webStream = Readable.toWeb(result.body) as unknown as ReadableStream<Uint8Array>

  return new Response(webStream, {
    headers: {
      'Content-Type': 'audio/mpeg',
      'Cache-Control': 'no-store',
      'X-Accel-Buffering': 'no',
    },
  })
}
