package com.unicorn.hgzero.stt.integration;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.unicorn.hgzero.stt.dto.RecordingDto;
import com.unicorn.hgzero.stt.dto.TranscriptionDto;
import com.unicorn.hgzero.stt.dto.SpeakerDto;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureWebMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.http.MediaType;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;
import org.springframework.transaction.annotation.Transactional;


import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;

/**
 * STT API 통합 테스트
 * 전체 워크플로우 시나리오 테스트
 */
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@AutoConfigureWebMvc
@ActiveProfiles("test")
@Transactional
@DisplayName("STT API 통합 테스트")
class SttApiIntegrationTest {
    
    @Autowired
    private MockMvc mockMvc;
    
    @Autowired
    private ObjectMapper objectMapper;
    
    @Test
    @DisplayName("전체 STT 워크플로우 통합 테스트")
    void fullSttWorkflowIntegrationTest() throws Exception {
        // 1단계: 녹음 준비
        RecordingDto.PrepareRequest prepareRequest = RecordingDto.PrepareRequest.builder()
                .meetingId("MEETING-INTEGRATION-001")
                .sessionId("SESSION-INTEGRATION-001")
                .language("ko-KR")
                .build();
        
        MvcResult prepareResult = mockMvc.perform(post("/api/v1/stt/recordings/prepare")
                        .contentType(MediaType.APPLICATION_JSON)
                        .content(objectMapper.writeValueAsString(prepareRequest)))
                .andExpect(status().isOk())
                .andExpect(jsonPath("$.success").value(true))
                .andExpect(jsonPath("$.data.status").value("READY"))
                .andReturn();
        
        // 응답에서 recordingId 추출
        String prepareResponseJson = prepareResult.getResponse().getContentAsString();
        // JSON 파싱하여 recordingId 추출 (실제로는 JsonPath 라이브러리 사용)
        String recordingId = "REC-20250123-001"; // 테스트용 하드코딩
        
        // 2단계: 녹음 시작
        RecordingDto.StartRequest startRequest = RecordingDto.StartRequest.builder()
                .startedBy("integration-test-user")
                .build();
        
        mockMvc.perform(post("/api/v1/stt/recordings/{recordingId}/start", recordingId)
                        .contentType(MediaType.APPLICATION_JSON)
                        .content(objectMapper.writeValueAsString(startRequest)))
                .andExpect(status().isOk())
                .andExpect(jsonPath("$.success").value(true))
                .andExpect(jsonPath("$.data.status").value("RECORDING"));
        
        // 3단계: 실시간 음성 변환 (시뮬레이션)
        TranscriptionDto.StreamRequest streamRequest = TranscriptionDto.StreamRequest.builder()
                .recordingId(recordingId)
                .audioData("dGVzdCBhdWRpbyBkYXRh") // base64 encoded "test audio data"
                .timestamp(System.currentTimeMillis())
                .chunkIndex(1)
                .build();
        
        mockMvc.perform(post("/api/v1/stt/transcription/stream")
                        .contentType(MediaType.APPLICATION_JSON)
                        .content(objectMapper.writeValueAsString(streamRequest)))
                .andExpect(status().isOk())
                .andExpect(jsonPath("$.success").value(true))
                .andExpect(jsonPath("$.data.recordingId").value(recordingId))
                .andExpect(jsonPath("$.data.text").exists())
                .andExpect(jsonPath("$.data.confidence").exists());
        
        // 4단계: 화자 식별
        SpeakerDto.IdentifyRequest identifyRequest = SpeakerDto.IdentifyRequest.builder()
                .recordingId(recordingId)
                .audioFrame("dGVzdCBhdWRpbyBmcmFtZQ==") // base64 encoded "test audio frame"
                .build();
        
        mockMvc.perform(post("/api/v1/stt/speakers/identify")
                        .contentType(MediaType.APPLICATION_JSON)
                        .content(objectMapper.writeValueAsString(identifyRequest)))
                .andExpect(status().isOk())
                .andExpect(jsonPath("$.success").value(true))
                .andExpect(jsonPath("$.data.speakerId").exists())
                .andExpect(jsonPath("$.data.confidence").exists());
        
        // 5단계: 녹음 중지
        RecordingDto.StopRequest stopRequest = RecordingDto.StopRequest.builder()
                .stoppedBy("integration-test-user")
                .build();
        
        mockMvc.perform(post("/api/v1/stt/recordings/{recordingId}/stop", recordingId)
                        .contentType(MediaType.APPLICATION_JSON)
                        .content(objectMapper.writeValueAsString(stopRequest)))
                .andExpect(status().isOk())
                .andExpect(jsonPath("$.success").value(true))
                .andExpect(jsonPath("$.data.status").value("STOPPED"))
                .andExpect(jsonPath("$.data.duration").exists());
        
        // 6단계: 녹음 정보 조회
        mockMvc.perform(get("/api/v1/stt/recordings/{recordingId}", recordingId))
                .andExpect(status().isOk())
                .andExpect(jsonPath("$.success").value(true))
                .andExpect(jsonPath("$.data.recordingId").value(recordingId))
                .andExpect(jsonPath("$.data.status").value("STOPPED"));
        
        // 7단계: 변환 결과 조회 (세그먼트 포함)
        mockMvc.perform(get("/api/v1/stt/transcription/{recordingId}", recordingId)
                        .param("includeSegments", "true"))
                .andExpect(status().isOk())
                .andExpect(jsonPath("$.success").value(true))
                .andExpect(jsonPath("$.data.recordingId").value(recordingId))
                .andExpect(jsonPath("$.data.fullText").exists());
        
        // 8단계: 녹음별 화자 목록 조회
        mockMvc.perform(get("/api/v1/stt/speakers/recordings/{recordingId}", recordingId))
                .andExpect(status().isOk())
                .andExpect(jsonPath("$.success").value(true))
                .andExpect(jsonPath("$.data.recordingId").value(recordingId))
                .andExpect(jsonPath("$.data.speakerCount").exists());
    }
    
    @Test
    @DisplayName("에러 케이스 통합 테스트")
    void errorCasesIntegrationTest() throws Exception {
        // 존재하지 않는 녹음 시작 시도
        RecordingDto.StartRequest startRequest = RecordingDto.StartRequest.builder()
                .startedBy("test-user")
                .build();
        
        mockMvc.perform(post("/api/v1/stt/recordings/NONEXISTENT-001/start")
                        .contentType(MediaType.APPLICATION_JSON)
                        .content(objectMapper.writeValueAsString(startRequest)))
                .andExpect(status().isBadRequest())
                .andExpect(jsonPath("$.success").value(false))
                .andExpect(jsonPath("$.message").exists());
        
        // 잘못된 요청 데이터로 녹음 준비 시도
        RecordingDto.PrepareRequest invalidRequest = RecordingDto.PrepareRequest.builder()
                .meetingId("") // 빈 meetingId
                .sessionId("SESSION-001")
                .build();
        
        mockMvc.perform(post("/api/v1/stt/recordings/prepare")
                        .contentType(MediaType.APPLICATION_JSON)
                        .content(objectMapper.writeValueAsString(invalidRequest)))
                .andExpect(status().isBadRequest());
        
        // 존재하지 않는 변환 결과 조회
        mockMvc.perform(get("/api/v1/stt/transcription/NONEXISTENT-001"))
                .andExpect(status().isBadRequest())
                .andExpect(jsonPath("$.success").value(false));
    }
    
    @Test
    @DisplayName("Swagger UI 접근 테스트")
    void swaggerUiAccessTest() throws Exception {
        // Swagger UI 페이지 접근 가능 여부 확인
        mockMvc.perform(get("/swagger-ui/index.html"))
                .andExpect(status().isOk());
        
        // OpenAPI JSON 엔드포인트 확인
        mockMvc.perform(get("/v3/api-docs"))
                .andExpect(status().isOk())
                .andExpect(content().contentType(MediaType.APPLICATION_JSON));
    }
}