<?php

namespace App\Services\Video;

use App\Models\System\AiConfig;
use App\Services\GoogleCloudService;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log;

class BgmService
{
    private GoogleCloudService $googleCloud;

    public function __construct(GoogleCloudService $googleCloud)
    {
        $this->googleCloud = $googleCloud;
    }

    /**
     * Google Lyria API로 AI 배경음악 생성
     *
     * @return string|null 생성된 MP3 파일 경로
     */
    public function generateWithLyria(string $mood, int $durationSec, string $savePath): ?string
    {
        $config = AiConfig::getActiveGemini();

        if (! $config || ! $config->isVertexAi()) {
            Log::info('BgmService: Vertex AI 설정 없음, Lyria 건너뜀');

            return null;
        }

        $token = $this->googleCloud->getAccessToken();

        if (! $token) {
            Log::warning('BgmService: Lyria 액세스 토큰 실패');

            return null;
        }

        try {
            $projectId = $config->getProjectId();
            $region = $config->getRegion();
            $prompt = $this->buildMusicPrompt($mood);

            $url = "https://{$region}-aiplatform.googleapis.com/v1/projects/{$projectId}/locations/{$region}/publishers/google/models/lyria:predict";

            Log::info('BgmService: Lyria API 요청', ['mood' => $mood, 'prompt' => $prompt]);

            $response = Http::withToken($token)
                ->timeout(120)
                ->post($url, [
                    'instances' => [
                        ['prompt' => $prompt],
                    ],
                ]);

            if (! $response->successful()) {
                Log::warning('BgmService: Lyria API 실패', [
                    'status' => $response->status(),
                    'body' => substr($response->body(), 0, 500),
                ]);

                return null;
            }

            $data = $response->json();
            $audioContent = $data['predictions'][0]['audioContent'] ?? null;

            if (! $audioContent) {
                Log::warning('BgmService: Lyria 응답에 오디오 없음');

                return null;
            }

            $dir = dirname($savePath);
            if (! is_dir($dir)) {
                mkdir($dir, 0755, true);
            }

            // WAV 저장 후 MP3 변환 + 영상 길이에 맞춤
            $wavPath = "{$dir}/bgm_lyria.wav";
            file_put_contents($wavPath, base64_decode($audioContent));

            // MP3 변환 + 영상 길이 맞춤 (30초 BGM이 짧으면 루프, 길면 트림)
            $cmd = sprintf(
                'ffmpeg -y -stream_loop -1 -i %s -t %d -af "afade=t=in:d=1,afade=t=out:st=%d:d=3" -c:a libmp3lame -q:a 2 %s 2>&1',
                escapeshellarg($wavPath),
                $durationSec,
                max(0, $durationSec - 3),
                escapeshellarg($savePath)
            );

            exec($cmd, $output, $returnCode);
            @unlink($wavPath);

            if ($returnCode !== 0) {
                Log::error('BgmService: Lyria WAV→MP3 변환 실패', [
                    'output' => implode("\n", array_slice($output, -5)),
                ]);

                return null;
            }

            Log::info('BgmService: Lyria BGM 생성 완료', [
                'path' => $savePath,
                'duration' => $durationSec,
            ]);

            return $savePath;
        } catch (\Exception $e) {
            Log::error('BgmService: Lyria 예외', ['error' => $e->getMessage()]);

            return null;
        }
    }

    /**
     * 분위기 → Lyria 영어 프롬프트 변환
     */
    private function buildMusicPrompt(string $mood): string
    {
        $prompts = [
            'upbeat' => 'Upbeat cheerful background music for a short health wellness video. Light electronic beat with positive energy, moderate tempo. Instrumental only, no vocals.',
            'energetic' => 'Energetic motivating background music for a fitness video. Fast-paced electronic beat with driving rhythm. Instrumental only, no vocals.',
            'exciting' => 'Exciting dynamic background music for a surprising facts video. Building tension with electronic elements. Instrumental only, no vocals.',
            'calm' => 'Calm soothing background music for a relaxation wellness video. Gentle piano and ambient pads, slow tempo. Instrumental only, no vocals.',
            'dramatic' => 'Dramatic cinematic background music for a revealing truth video. Orchestral tension with building suspense. Instrumental only, no vocals.',
            'happy' => 'Happy bright background music for a positive health tips video. Cheerful ukulele and light percussion. Instrumental only, no vocals.',
            'mysterious' => 'Mysterious intriguing background music for a health secrets video. Dark ambient with subtle electronic textures. Instrumental only, no vocals.',
            'inspiring' => 'Inspiring uplifting background music for a motivational health video. Warm piano with gentle strings, building progression. Instrumental only, no vocals.',
        ];

        $moodLower = strtolower($mood);

        foreach ($prompts as $key => $prompt) {
            if (str_contains($moodLower, $key)) {
                return $prompt;
            }
        }

        return 'Light pleasant background music for a short health video. Moderate tempo, positive mood, gentle electronic beat. Instrumental only, no vocals.';
    }

    /**
     * 분위기별 BGM 매핑 (로열티프리 BGM 파일 풀)
     * storage/app/bgm/ 디렉토리에 미리 준비
     */
    private array $moodMap = [
        'upbeat' => ['upbeat_01.mp3', 'upbeat_02.mp3'],
        'energetic' => ['energetic_01.mp3', 'energetic_02.mp3'],
        'exciting' => ['exciting_01.mp3', 'exciting_02.mp3'],
        'calm' => ['calm_01.mp3', 'calm_02.mp3'],
        'dramatic' => ['dramatic_01.mp3', 'dramatic_02.mp3'],
        'happy' => ['happy_01.mp3', 'happy_02.mp3'],
        'sad' => ['sad_01.mp3', 'sad_02.mp3'],
        'mysterious' => ['mysterious_01.mp3', 'mysterious_02.mp3'],
        'inspiring' => ['inspiring_01.mp3', 'inspiring_02.mp3'],
    ];

    /**
     * 분위기에 맞는 BGM 선택
     *
     * @return string|null BGM 파일 경로
     */
    public function select(string $mood, string $savePath): ?string
    {
        $bgmDir = storage_path('app/bgm');

        // 분위기 키워드 매칭 (부분 일치 지원)
        $matchedFiles = [];
        $moodLower = strtolower($mood);

        foreach ($this->moodMap as $key => $files) {
            if (str_contains($moodLower, $key)) {
                $matchedFiles = array_merge($matchedFiles, $files);
            }
        }

        // 매칭되는 분위기가 없으면 기본값
        if (empty($matchedFiles)) {
            $matchedFiles = $this->moodMap['upbeat'] ?? ['default.mp3'];
        }

        // 랜덤 선택
        $selectedFile = $matchedFiles[array_rand($matchedFiles)];
        $sourcePath = "{$bgmDir}/{$selectedFile}";

        // BGM 파일 존재 확인
        if (! file_exists($sourcePath)) {
            Log::warning('BgmService: BGM 파일 없음', [
                'path' => $sourcePath,
                'mood' => $mood,
            ]);

            // BGM 디렉토리에서 아무 파일이나 선택
            return $this->selectFallback($bgmDir, $savePath);
        }

        $dir = dirname($savePath);
        if (! is_dir($dir)) {
            mkdir($dir, 0755, true);
        }

        copy($sourcePath, $savePath);

        Log::info('BgmService: BGM 선택 완료', [
            'mood' => $mood,
            'file' => $selectedFile,
        ]);

        return $savePath;
    }

    /**
     * 폴백: BGM 디렉토리에서 아무 MP3 선택
     */
    private function selectFallback(string $bgmDir, string $savePath): ?string
    {
        if (! is_dir($bgmDir)) {
            Log::error('BgmService: BGM 디렉토리 없음', ['dir' => $bgmDir]);

            return null;
        }

        $files = glob("{$bgmDir}/*.mp3");

        if (empty($files)) {
            Log::error('BgmService: BGM 파일이 하나도 없음');

            return null;
        }

        $selected = $files[array_rand($files)];

        $dir = dirname($savePath);
        if (! is_dir($dir)) {
            mkdir($dir, 0755, true);
        }

        copy($selected, $savePath);

        return $savePath;
    }

    /**
     * 분위기별 앰비언트 BGM 생성 (FFmpeg 사용, BGM 파일이 없을 때 폴백)
     *
     * 로컬 BGM 파일이 없을 때 FFmpeg의 오디오 합성으로 간단한 앰비언트 배경음 생성
     */
    public function generateAmbient(string $mood, int $durationSec, string $savePath): ?string
    {
        $dir = dirname($savePath);
        if (! is_dir($dir)) {
            mkdir($dir, 0755, true);
        }

        // 분위기별 코드 주파수 설정 (근음, 3도, 5도, 옥타브)
        $chords = $this->getMoodChord($mood);

        // FFmpeg aevalsrc로 화음 + 볼륨 모듈레이션(호흡 효과) 생성
        $expr = '';
        foreach ($chords as $i => $freq) {
            $vol = 0.06 - ($i * 0.01); // 각 음의 볼륨을 점차 줄여 자연스럽게
            $modFreq = 0.08 + ($i * 0.03); // 각 음의 떨림 속도를 다르게
            $expr .= ($expr ? ' + ' : '')."{$vol}*sin({$freq}*2*PI*t)*((0.5+0.5*sin({$modFreq}*2*PI*t)))";
        }

        // 페이드인(3초) + 페이드아웃(3초) 추가
        $cmd = sprintf(
            'ffmpeg -y -f lavfi -i "aevalsrc=%s:s=44100:d=%d" '
            .'-af "lowpass=f=1500,highpass=f=80,afade=t=in:d=3,afade=t=out:st=%d:d=3" '
            .'-c:a libmp3lame -q:a 4 %s 2>&1',
            escapeshellarg($expr),
            $durationSec + 2, // 페이드아웃 여유분
            max(0, $durationSec - 2),
            escapeshellarg($savePath)
        );

        Log::info('BgmService: 앰비언트 BGM 생성 시작', ['mood' => $mood, 'duration' => $durationSec]);

        exec($cmd, $output, $returnCode);

        if ($returnCode !== 0) {
            Log::error('BgmService: 앰비언트 BGM 생성 실패, 무음 폴백', [
                'output' => implode("\n", array_slice($output, -10)),
            ]);

            return $this->generateSilence($durationSec, $savePath);
        }

        Log::info('BgmService: 앰비언트 BGM 생성 완료', ['path' => $savePath]);

        return $savePath;
    }

    /**
     * 분위기별 화음 주파수 반환
     */
    private function getMoodChord(string $mood): array
    {
        $moodLower = strtolower($mood);

        // 분위기별 코드 (근음 기준 메이저/마이너 코드)
        if (str_contains($moodLower, 'sad') || str_contains($moodLower, 'dramatic')) {
            // A minor (La-Do-Mi) - 슬프거나 극적인 분위기
            return [220.00, 261.63, 329.63, 440.00];
        }
        if (str_contains($moodLower, 'calm') || str_contains($moodLower, 'mysterious')) {
            // D minor7 (Re-Fa-La-Do) - 잔잔하거나 신비로운 분위기
            return [146.83, 174.61, 220.00, 261.63];
        }
        if (str_contains($moodLower, 'inspiring') || str_contains($moodLower, 'happy')) {
            // G major (Sol-Si-Re) - 영감을 주거나 밝은 분위기
            return [196.00, 246.94, 293.66, 392.00];
        }

        // 기본: C major (Do-Mi-Sol) - 밝고 에너지 넘치는 분위기
        return [130.81, 164.81, 196.00, 261.63];
    }

    /**
     * 무음 BGM 생성 (FFmpeg 사용, 최종 폴백)
     */
    public function generateSilence(int $durationSec, string $savePath): ?string
    {
        $dir = dirname($savePath);
        if (! is_dir($dir)) {
            mkdir($dir, 0755, true);
        }

        $cmd = sprintf(
            'ffmpeg -y -f lavfi -i anullsrc=r=44100:cl=stereo -t %d -c:a libmp3lame -q:a 9 %s 2>&1',
            $durationSec,
            escapeshellarg($savePath)
        );

        exec($cmd, $output, $returnCode);

        if ($returnCode !== 0) {
            Log::error('BgmService: 무음 BGM 생성 실패', ['output' => implode("\n", $output)]);

            return null;
        }

        return $savePath;
    }
}
