package com.unicorn.hgzero.meeting.infra.controller;

import com.unicorn.hgzero.common.dto.ApiResponse;
import com.unicorn.hgzero.common.exception.BusinessException;
import com.unicorn.hgzero.common.exception.ErrorCode;
import com.unicorn.hgzero.meeting.biz.dto.MeetingDTO;
import com.unicorn.hgzero.meeting.biz.dto.MeetingEndDTO;
import com.unicorn.hgzero.meeting.biz.usecase.in.meeting.*;
import com.unicorn.hgzero.meeting.infra.dto.request.CreateMeetingRequest;
import com.unicorn.hgzero.meeting.infra.dto.request.InviteParticipantRequest;
import com.unicorn.hgzero.meeting.infra.dto.request.SelectTemplateRequest;
import com.unicorn.hgzero.meeting.infra.dto.response.InviteParticipantResponse;
import com.unicorn.hgzero.meeting.infra.dto.response.MeetingResponse;
import com.unicorn.hgzero.meeting.infra.dto.response.MeetingEndResponse;
import com.unicorn.hgzero.meeting.infra.dto.response.SessionResponse;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import jakarta.validation.Valid;
import java.util.List;

/**
 * 회의 관리 REST API Controller
 * 회의 예약, 시작, 종료, 템플릿 적용 등 회의 관련 기능 제공
 */
@Tag(name = "Meeting", description = "회의 관리 API")
@RestController
@RequestMapping("/api/meetings")
@RequiredArgsConstructor
@Slf4j
public class MeetingController {

    private final CreateMeetingUseCase createMeetingUseCase;
    private final StartMeetingUseCase startMeetingUseCase;
    private final EndMeetingUseCase endMeetingUseCase;
    private final GetMeetingUseCase getMeetingUseCase;
    private final CancelMeetingUseCase cancelMeetingUseCase;
    private final InviteParticipantUseCase inviteParticipantUseCase;
    private final ApplyTemplateUseCase applyTemplateUseCase;

    /**
     * 회의 예약
     * 
     * @param userId 사용자 ID
     * @param request 회의 생성 요청
     * @return 생성된 회의 정보
     */
    @Operation(
        summary = "회의 예약",
        description = "새로운 회의를 예약하고 참석자를 초대합니다. 회의 정보 저장, 참석자 목록 관리, 초대 이메일 자동 발송, 리마인더 스케줄링을 수행합니다.",
        security = @SecurityRequirement(name = "bearerAuth")
    )
    @PostMapping
    public ResponseEntity<ApiResponse<MeetingResponse>> createMeeting(
            @Parameter(description = "사용자 ID", required = true)
            @RequestHeader("X-User-Id") String userId,
            @Parameter(description = "사용자명", required = true)
            @RequestHeader("X-User-Name") String userName,
            @Parameter(description = "사용자 이메일", required = true)
            @RequestHeader("X-User-Email") String userEmail,
            @Valid @RequestBody CreateMeetingRequest request) {
        
        log.info("회의 예약 요청 - userId: {}, title: {}", userId, request.getTitle());
        
        var meetingData = createMeetingUseCase.createMeeting(
            new CreateMeetingUseCase.CreateMeetingCommand(
                request.getTitle(),
                request.getPurpose(),
                request.getAgenda(),
                request.getStartTime(),
                request.getEndTime(),
                request.getLocation(),
                userId,
                request.getParticipants(),
                null // 템플릿 ID는 나중에 적용
            )
        );
        
        var meetingDTO = MeetingDTO.from(meetingData);
        var response = MeetingResponse.from(meetingDTO);
        
        log.info("회의 예약 완료 - userId: {}, meetingId: {}", userId, meetingData.getMeetingId());
        
        return ResponseEntity.status(HttpStatus.CREATED)
                .body(ApiResponse.success(response));
    }

    /**
     * 회의록 템플릿 선택
     * 
     * @param meetingId 회의 ID
     * @param userId 사용자 ID
     * @param request 템플릿 선택 요청
     * @return 회의 정보
     */
    @Operation(
        summary = "회의록 템플릿 선택",
        description = "회의에 회의록 템플릿을 적용합니다. 템플릿 유형으로는 일반 회의, 스크럼, 프로젝트 킥오프, 주간 회의가 있으며 섹션 커스터마이징이 가능합니다.",
        security = @SecurityRequirement(name = "bearerAuth")
    )
    @PutMapping("/{meetingId}/template")
    public ResponseEntity<ApiResponse<MeetingResponse>> applyTemplate(
            @Parameter(description = "회의 ID", required = true)
            @PathVariable String meetingId,
            @Parameter(description = "사용자 ID", required = true)
            @RequestHeader("X-User-Id") String userId,
            @Parameter(description = "사용자명", required = true)
            @RequestHeader("X-User-Name") String userName,
            @Parameter(description = "사용자 이메일", required = true)
            @RequestHeader("X-User-Email") String userEmail,
            @Valid @RequestBody SelectTemplateRequest request) {
        
        log.info("템플릿 적용 요청 - meetingId: {}, templateId: {}", meetingId, request.getTemplateId());
        
        var meetingData = applyTemplateUseCase.applyTemplate(
            new ApplyTemplateUseCase.ApplyTemplateCommand(
                meetingId,
                request.getTemplateId()
            )
        );
        
        var meetingDTO = MeetingDTO.from(meetingData);
        var response = MeetingResponse.from(meetingDTO);
        
        log.info("템플릿 적용 완료 - meetingId: {}, templateId: {}", meetingId, request.getTemplateId());
        
        return ResponseEntity.ok(ApiResponse.success(response));
    }

    /**
     * 회의 시작
     * 
     * @param meetingId 회의 ID
     * @param userId 사용자 ID
     * @return 세션 정보
     */
    @Operation(
        summary = "회의 시작",
        description = "예약된 회의를 시작하고 회의록 작성 세션을 생성합니다. 실시간 협업을 위한 WebSocket 세션이 활성화됩니다.",
        security = @SecurityRequirement(name = "bearerAuth")
    )
    @PostMapping("/{meetingId}/start")
    public ResponseEntity<ApiResponse<SessionResponse>> startMeeting(
            @Parameter(description = "회의 ID", required = true)
            @PathVariable String meetingId,
            @Parameter(description = "사용자 ID", required = true)
            @RequestHeader("X-User-Id") String userId,
            @Parameter(description = "사용자명", required = true)
            @RequestHeader("X-User-Name") String userName,
            @Parameter(description = "사용자 이메일", required = true)
            @RequestHeader("X-User-Email") String userEmail) {
        
        log.info("회의 시작 요청 - meetingId: {}, userId: {}", meetingId, userId);

        // meeting id 유효성 검증 필요

        var session = startMeetingUseCase.startMeeting(meetingId);
        var response = SessionResponse.from(session, "ws://localhost:8080/ws/collaboration");

        log.info("회의 시작 완료 - meetingId: {}, sessionId: {}", meetingId, session.getSessionId());

        return ResponseEntity.status(HttpStatus.CREATED).body(ApiResponse.success(response));
    }

    /**
     * 회의 종료
     * 
     * @param meetingId 회의 ID
     * @param userId 사용자 ID
     * @return 회의 종료 결과
     */
    @Operation(
        summary = "회의 종료",
        description = "진행 중인 회의를 종료하고 AI 분석을 통해 회의록을 생성합니다. 주요 키워드 추출, 안건별 요약, Todo 자동 추출이 수행됩니다.",
        security = @SecurityRequirement(name = "bearerAuth")
    )
    @PostMapping("/{meetingId}/end")
    public ResponseEntity<ApiResponse<MeetingEndResponse>> endMeeting(
            @Parameter(description = "회의 ID", required = true)
            @PathVariable String meetingId,
            @Parameter(description = "사용자 ID", required = true)
            @RequestHeader("X-User-Id") String userId,
            @Parameter(description = "사용자명", required = true)
            @RequestHeader("X-User-Name") String userName,
            @Parameter(description = "사용자 이메일", required = true)
            @RequestHeader("X-User-Email") String userEmail) {
        
        log.info("회의 종료 요청 - meetingId: {}, userId: {}", meetingId, userId);
        
        try {
            // 실제 비즈니스 로직 호출
            MeetingEndDTO meetingEndDTO = endMeetingUseCase.endMeeting(meetingId);
            
            // DTO를 응답 객체로 변환
            MeetingEndResponse response = MeetingEndResponse.from(meetingEndDTO);
            
            log.info("회의 종료 완료 - meetingId: {}", meetingId);
            return ResponseEntity.ok(ApiResponse.success(response));
            
        } catch (BusinessException e) {
            log.error("회의 종료 실패 - meetingId: {}, error: {}", meetingId, e.getMessage());
            throw e;
        } catch (Exception e) {
            log.error("회의 종료 중 예상치 못한 오류 - meetingId: {}", meetingId, e);
            throw new BusinessException(ErrorCode.INTERNAL_SERVER_ERROR, "회의 종료 처리 중 오류가 발생했습니다.");
        }
    }


    /**
     * 회의 정보 조회
     * 
     * @param meetingId 회의 ID
     * @return 회의 정보
     */
    @Operation(
        summary = "회의 정보 조회",
        description = "특정 회의의 상세 정보를 조회합니다.",
        security = @SecurityRequirement(name = "bearerAuth")
    )
    @GetMapping("/{meetingId}")
    public ResponseEntity<ApiResponse<MeetingResponse>> getMeeting(
            @Parameter(description = "회의 ID", required = true)
            @PathVariable String meetingId,
            @Parameter(description = "사용자 ID", required = true)
            @RequestHeader("X-User-Id") String userId) {
        
        log.info("회의 정보 조회 요청 - meetingId: {}", meetingId);
        
        var meetingData = getMeetingUseCase.getMeeting(meetingId);
        var meetingDTO = MeetingDTO.from(meetingData);
        var response = MeetingResponse.from(meetingDTO);
        
        log.info("회의 정보 조회 완료 - meetingId: {}", meetingId);
        
        return ResponseEntity.ok(ApiResponse.success(response));
    }

    /**
     * 회의 취소
     * 
     * @param meetingId 회의 ID
     * @param userId 사용자 ID
     * @return 성공 응답
     */
    @Operation(
        summary = "회의 취소",
        description = "예약된 회의를 취소합니다.",
        security = @SecurityRequirement(name = "bearerAuth")
    )
    @DeleteMapping("/{meetingId}")
    public ResponseEntity<ApiResponse<Void>> cancelMeeting(
            @Parameter(description = "회의 ID", required = true)
            @PathVariable String meetingId,
            @Parameter(description = "사용자 ID", required = true)
            @RequestHeader("X-User-Id") String userId) {
        
        log.info("회의 취소 요청 - meetingId: {}, userId: {}", meetingId, userId);
        
        cancelMeetingUseCase.cancelMeeting(meetingId);
        
        log.info("회의 취소 완료 - meetingId: {}", meetingId);
        
        return ResponseEntity.ok(ApiResponse.success(null));
    }

    /**
     * 회의 참석자 초대
     *
     * @param meetingId 회의 ID
     * @param userId 사용자 ID
     * @param userName 사용자명
     * @param userEmail 사용자 이메일
     * @param request 참석자 초대 요청
     * @return 초대 결과
     */
    @Operation(
        summary = "회의 참석자 초대",
        description = "진행 중이거나 예약된 회의에 새로운 참석자를 초대합니다. 초대된 참석자에게는 회의록 프론트엔드 URL과 함께 이메일이 발송됩니다.",
        security = @SecurityRequirement(name = "bearerAuth")
    )
    @PostMapping("/{meetingId}/invite")
    public ResponseEntity<ApiResponse<InviteParticipantResponse>> inviteParticipant(
            @Parameter(description = "회의 ID", required = true)
            @PathVariable String meetingId,
            @Parameter(description = "사용자 ID", required = true)
            @RequestHeader("X-User-Id") String userId,
            @Parameter(description = "사용자명", required = true)
            @RequestHeader("X-User-Name") String userName,
            @Parameter(description = "사용자 이메일", required = true)
            @RequestHeader("X-User-Email") String userEmail,
            @Valid @RequestBody InviteParticipantRequest request) {

        log.info("참석자 초대 요청 - meetingId: {}, email: {}, inviter: {}",
                meetingId, request.getEmail(), userName);

        // 프론트엔드 URL 생성 (실제 환경에서는 설정에서 가져와야 함)
        String frontendUrl = "https://meeting.hgzero.com/meeting/" + meetingId;

        inviteParticipantUseCase.inviteParticipant(
            new InviteParticipantUseCase.InviteParticipantCommand(
                meetingId,
                request.getEmail(),
                userName,
                frontendUrl
            )
        );

        var response = InviteParticipantResponse.of(meetingId, request.getEmail());

        log.info("참석자 초대 완료 - meetingId: {}, email: {}", meetingId, request.getEmail());

        return ResponseEntity.ok(ApiResponse.success(response));
    }
}