<?php

namespace App\Services;

use App\Helpers\AiTokenHelper;
use App\Models\MeetingLog;
use Illuminate\Pagination\LengthAwarePaginator;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log;

/**
 * 회의록 서비스 (웹 녹음 AI 요약)
 */
class MeetingLogService
{
    public function __construct(
        private GoogleCloudService $googleCloudService
    ) {}

    /**
     * 회의록 목록 조회
     */
    public function getList(array $params = []): LengthAwarePaginator
    {
        $query = MeetingLog::query()
            ->with('user:id,name')
            ->orderBy('created_at', 'desc');

        // 상태 필터
        if (! empty($params['status'])) {
            $query->where('status', $params['status']);
        }

        // 검색어
        if (! empty($params['search'])) {
            $search = $params['search'];
            $query->where(function ($q) use ($search) {
                $q->where('title', 'like', "%{$search}%")
                    ->orWhere('transcript_text', 'like', "%{$search}%")
                    ->orWhere('summary_text', 'like', "%{$search}%");
            });
        }

        $perPage = $params['per_page'] ?? 10;

        return $query->paginate($perPage);
    }

    /**
     * 회의록 상세 조회
     */
    public function getById(int $id): ?MeetingLog
    {
        return MeetingLog::with('user:id,name')->find($id);
    }

    /**
     * 회의록 생성 (녹음 시작)
     */
    public function create(array $data): MeetingLog
    {
        return MeetingLog::create([
            'tenant_id' => session('selected_tenant_id'),
            'user_id' => Auth::id(),
            'title' => $data['title'] ?? '무제 회의록',
            'status' => MeetingLog::STATUS_PENDING,
            'file_expiry_date' => now()->addDays(7),
        ]);
    }

    /**
     * 오디오 업로드 및 처리 시작
     */
    public function processAudio(MeetingLog $meeting, string $audioBase64, int $durationSeconds): array
    {
        try {
            // 상태 업데이트
            $meeting->update([
                'status' => MeetingLog::STATUS_PROCESSING,
                'duration_seconds' => $durationSeconds,
            ]);

            // 1. GCS에 오디오 업로드
            $objectName = sprintf(
                'meetings/%d/%d/%s.webm',
                $meeting->tenant_id,
                $meeting->id,
                now()->format('YmdHis')
            );

            $uploadResult = $this->googleCloudService->uploadBase64Audio($audioBase64, $objectName);

            if (! $uploadResult) {
                throw new \Exception('오디오 파일 업로드 실패');
            }

            $gcsUri = $uploadResult['uri'];

            $meeting->update([
                'audio_file_path' => $objectName,
                'audio_gcs_uri' => $gcsUri,
            ]);

            // 2. Speech-to-Text 변환
            $transcript = $this->googleCloudService->speechToText($gcsUri);

            if (! $transcript) {
                throw new \Exception('음성 인식 실패');
            }

            $meeting->update(['transcript_text' => $transcript]);

            // 3. AI 요약 생성
            $summary = $this->generateSummary($transcript);

            $meeting->update([
                'summary_text' => $summary,
                'status' => MeetingLog::STATUS_COMPLETED,
            ]);

            return [
                'ok' => true,
                'meeting' => $meeting->fresh(),
            ];
        } catch (\Exception $e) {
            Log::error('MeetingLog 처리 실패', [
                'meeting_id' => $meeting->id,
                'error' => $e->getMessage(),
            ]);

            $meeting->update(['status' => MeetingLog::STATUS_FAILED]);

            return [
                'ok' => false,
                'error' => $e->getMessage(),
            ];
        }
    }

    /**
     * AI 요약 생성 (Claude API)
     *
     * @param  string  $summaryType  meeting|work-memo
     */
    private function generateSummary(string $transcript, string $summaryType = 'meeting'): ?string
    {
        $apiKey = config('services.claude.api_key');
        if (empty($apiKey)) {
            Log::warning('Claude API 키 미설정');

            return null;
        }

        $prompt = $summaryType === 'work-memo'
            ? $this->buildWorkMemoPrompt($transcript)
            : $this->buildSummaryPrompt($transcript);

        try {
            $response = Http::withHeaders([
                'x-api-key' => $apiKey,
                'anthropic-version' => '2023-06-01',
            ])->post('https://api.anthropic.com/v1/messages', [
                'model' => 'claude-3-haiku-20240307',
                'max_tokens' => 4096,
                'messages' => [
                    [
                        'role' => 'user',
                        'content' => $prompt,
                    ],
                ],
            ]);

            if ($response->successful()) {
                $data = $response->json();

                // 토큰 사용량 저장
                AiTokenHelper::saveClaudeUsage($data, 'claude-3-haiku-20240307', '회의록AI요약');

                return $data['content'][0]['text'] ?? null;
            }

            Log::error('Claude API 요청 실패', ['response' => $response->body()]);

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

            return null;
        }
    }

    /**
     * 요약 프롬프트 생성 (일반 회의록)
     */
    private function buildSummaryPrompt(string $transcript): string
    {
        return <<<PROMPT
다음은 회의 녹음을 텍스트로 변환한 내용입니다. 이 내용을 바탕으로 구조화된 회의록을 작성해주세요.

## 요청사항:
1. **회의 요약**: 핵심 내용을 3-5문장으로 요약
2. **주요 논의 사항**: 논의된 주요 주제들을 항목별로 정리
3. **결정 사항**: 회의에서 결정된 내용들
4. **액션 아이템**: 후속 조치가 필요한 항목들 (담당자, 기한 등이 언급되었다면 포함)
5. **참고 사항**: 기타 중요한 내용

## 회의 녹취록:
{$transcript}

## 회의록:
PROMPT;
    }

    /**
     * 업무협의록 프롬프트 생성 (고객사 미팅용)
     */
    private function buildWorkMemoPrompt(string $transcript): string
    {
        return <<<PROMPT
다음은 고객사와의 업무 협의 미팅 녹음을 텍스트로 변환한 내용입니다. 이 내용을 바탕으로 구조화된 업무협의록을 작성해주세요.

## 요청사항:
1. **협의 개요**: 미팅의 목적과 핵심 내용을 3-5문장으로 요약
2. **고객 요구사항**: 고객이 요청하거나 원하는 사항들을 구체적으로 정리
3. **합의 사항**: 양측이 합의한 내용들 (범위, 일정, 비용, 조건 등)
4. **미결 사항**: 추가 검토가 필요하거나 결정되지 않은 사항들
5. **후속 조치 (To-Do)**:
   - 우리측 조치: 담당자, 기한, 세부 내용
   - 고객측 조치: 담당자, 기한, 세부 내용
6. **특이사항/리스크**: 주의가 필요한 사항이나 잠재적 위험 요소

## 협의 녹취록:
{$transcript}

## 업무협의록:
PROMPT;
    }

    /**
     * 회의록 삭제
     */
    public function delete(MeetingLog $meeting): bool
    {
        // GCS 파일 삭제
        if ($meeting->audio_file_path) {
            $this->googleCloudService->deleteFromStorage($meeting->audio_file_path);
        }

        return $meeting->delete();
    }

    /**
     * 제목 업데이트
     */
    public function updateTitle(MeetingLog $meeting, string $title): MeetingLog
    {
        $meeting->update(['title' => $title]);

        return $meeting->fresh();
    }

    /**
     * 만료된 파일 정리 (Cron Job용)
     */
    public function cleanupExpiredFiles(): int
    {
        $expired = MeetingLog::where('file_expiry_date', '<=', now())
            ->whereNotNull('audio_file_path')
            ->get();

        $count = 0;
        foreach ($expired as $meeting) {
            if ($meeting->audio_file_path) {
                $this->googleCloudService->deleteFromStorage($meeting->audio_file_path);
                $meeting->update([
                    'audio_file_path' => null,
                    'audio_gcs_uri' => null,
                ]);
                $count++;
            }
        }

        return $count;
    }

    /**
     * 업로드된 오디오 파일 처리 (회의록 AI 요약)
     *
     * @param  string  $summaryType  meeting|work-memo
     */
    public function processUploadedFile(MeetingLog $meeting, \Illuminate\Http\UploadedFile $file, string $summaryType = 'meeting'): array
    {
        try {
            $meeting->update(['status' => MeetingLog::STATUS_PROCESSING]);

            // 임시 저장
            $tempPath = $file->store('temp', 'local');
            $fullPath = storage_path('app/'.$tempPath);

            // 파일 크기로 대략적인 재생 시간 추정 (12KB/초 기준)
            $fileSize = $file->getSize();
            $estimatedDuration = max(1, intval($fileSize / 12000));
            $meeting->update(['duration_seconds' => $estimatedDuration]);

            // 1. GCS에 오디오 업로드
            $extension = $file->getClientOriginalExtension() ?: 'webm';
            $objectName = sprintf(
                'meetings/%d/%d/%s.%s',
                $meeting->tenant_id,
                $meeting->id,
                now()->format('YmdHis'),
                $extension
            );

            $uploadResult = $this->googleCloudService->uploadToStorage($fullPath, $objectName);

            if (! $uploadResult) {
                @unlink($fullPath);
                throw new \Exception('오디오 파일 업로드 실패');
            }

            $gcsUri = $uploadResult['uri'];

            $meeting->update([
                'audio_file_path' => $objectName,
                'audio_gcs_uri' => $gcsUri,
            ]);

            // 2. Speech-to-Text 변환
            $transcript = $this->googleCloudService->speechToText($gcsUri);

            // 임시 파일 삭제
            @unlink($fullPath);

            if (! $transcript) {
                throw new \Exception('음성 인식 실패');
            }

            $meeting->update(['transcript_text' => $transcript]);

            // 3. AI 요약 생성 (summaryType에 따라 프롬프트 선택)
            $summary = $this->generateSummary($transcript, $summaryType);

            $meeting->update([
                'summary_text' => $summary,
                'status' => MeetingLog::STATUS_COMPLETED,
            ]);

            return [
                'ok' => true,
                'meeting' => $meeting->fresh(),
            ];
        } catch (\Exception $e) {
            Log::error('MeetingLog 파일 처리 실패', [
                'meeting_id' => $meeting->id,
                'error' => $e->getMessage(),
            ]);

            $meeting->update(['status' => MeetingLog::STATUS_FAILED]);

            return [
                'ok' => false,
                'error' => $e->getMessage(),
            ];
        }
    }
}
