package com.unicorn.hgzero.meeting.biz.service;

import com.unicorn.hgzero.common.exception.BusinessException;
import com.unicorn.hgzero.common.exception.ErrorCode;
import com.unicorn.hgzero.meeting.biz.domain.MinutesSection;
import com.unicorn.hgzero.meeting.biz.usecase.in.section.*;
import com.unicorn.hgzero.meeting.biz.usecase.out.MinutesSectionReader;
import com.unicorn.hgzero.meeting.biz.usecase.out.MinutesSectionWriter;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.UUID;

/**
 * 회의록 섹션 Service
 * MinutesSection 관련 모든 UseCase 구현
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class MinutesSectionService implements
        CreateSectionUseCase,
        UpdateSectionUseCase,
        DeleteSectionUseCase,
        LockSectionUseCase,
        VerifySectionUseCase,
        GetSectionUseCase {

    private final MinutesSectionReader sectionReader;
    private final MinutesSectionWriter sectionWriter;

    /**
     * 섹션 생성
     */
    @Override
    @Transactional
    public MinutesSection createSection(CreateSectionCommand command) {
        log.info("Creating section for minutes: {}", command.minutesId());

        // 섹션 ID 생성
        String sectionId = UUID.randomUUID().toString();

        // 섹션 도메인 객체 생성
        MinutesSection section = MinutesSection.builder()
                .sectionId(sectionId)
                .minutesId(command.minutesId())
                .type(command.type())
                .title(command.title())
                .content(command.content())
                .order(command.order())
                .verified(false)
                .locked(false)
                .build();

        // 섹션 저장
        MinutesSection savedSection = sectionWriter.save(section);

        log.info("Section created successfully: {}", savedSection.getSectionId());
        return savedSection;
    }

    /**
     * 섹션 내용 수정
     */
    @Override
    @Transactional
    public MinutesSection updateSection(UpdateSectionCommand command) {
        log.info("Updating section: {}", command.sectionId());

        // 섹션 조회
        MinutesSection section = sectionReader.findById(command.sectionId())
                .orElseThrow(() -> new BusinessException(ErrorCode.ENTITY_NOT_FOUND));

        // 잠금 상태 검증
        if (Boolean.TRUE.equals(section.getLocked())) {
            throw new BusinessException(ErrorCode.INVALID_INPUT_VALUE);
        }

        // 검증 상태 검증
        if (Boolean.TRUE.equals(section.getVerified())) {
            throw new BusinessException(ErrorCode.INVALID_INPUT_VALUE);
        }

        // 섹션 수정
        section.update(command.title(), command.content());

        // 저장
        MinutesSection updatedSection = sectionWriter.save(section);

        log.info("Section updated successfully: {}", command.sectionId());
        return updatedSection;
    }

    /**
     * 섹션 삭제
     */
    @Override
    @Transactional
    public void deleteSection(String sectionId) {
        log.info("Deleting section: {}", sectionId);

        // 섹션 조회
        MinutesSection section = sectionReader.findById(sectionId)
                .orElseThrow(() -> new BusinessException(ErrorCode.ENTITY_NOT_FOUND));

        // 검증 상태 확인 (검증된 섹션은 삭제 불가)
        if (Boolean.TRUE.equals(section.getVerified())) {
            throw new BusinessException(ErrorCode.INVALID_INPUT_VALUE);
        }

        // 섹션 삭제
        sectionWriter.delete(sectionId);

        log.info("Section deleted successfully: {}", sectionId);
    }

    /**
     * 섹션 잠금
     */
    @Override
    @Transactional
    public MinutesSection lockSection(String sectionId, String userId) {
        log.info("Locking section: {} by user: {}", sectionId, userId);

        // 섹션 조회
        MinutesSection section = sectionReader.findById(sectionId)
                .orElseThrow(() -> new BusinessException(ErrorCode.ENTITY_NOT_FOUND));

        // 이미 잠금 상태 확인
        if (Boolean.TRUE.equals(section.getLocked())) {
            throw new BusinessException(ErrorCode.INVALID_INPUT_VALUE);
        }

        // 섹션 잠금
        section.lock(userId);

        // 저장
        MinutesSection lockedSection = sectionWriter.save(section);

        log.info("Section locked successfully: {}", sectionId);
        return lockedSection;
    }

    /**
     * 섹션 잠금 해제
     */
    @Override
    @Transactional
    public MinutesSection unlockSection(String sectionId) {
        log.info("Unlocking section: {}", sectionId);

        // 섹션 조회
        MinutesSection section = sectionReader.findById(sectionId)
                .orElseThrow(() -> new BusinessException(ErrorCode.ENTITY_NOT_FOUND));

        // 잠금 상태 확인
        if (Boolean.FALSE.equals(section.getLocked())) {
            throw new BusinessException(ErrorCode.INVALID_INPUT_VALUE);
        }

        // 섹션 잠금 해제
        section.unlock();

        // 저장
        MinutesSection unlockedSection = sectionWriter.save(section);

        log.info("Section unlocked successfully: {}", sectionId);
        return unlockedSection;
    }

    /**
     * 섹션 잠금 해제 (사용자 ID 포함)
     */
    @Transactional
    public MinutesSection unlockSection(String sectionId, String userId) {
        log.info("Unlocking section: {} by user: {}", sectionId, userId);

        // 권한 검증 등 추가 로직이 필요하면 여기에 구현
        return unlockSection(sectionId);
    }

    /**
     * 섹션 검증
     */
    @Override
    @Transactional
    public MinutesSection verifySection(String sectionId) {
        log.info("Verifying section: {}", sectionId);

        // 섹션 조회
        MinutesSection section = sectionReader.findById(sectionId)
                .orElseThrow(() -> new BusinessException(ErrorCode.ENTITY_NOT_FOUND));

        // 이미 검증 상태 확인
        if (Boolean.TRUE.equals(section.getVerified())) {
            throw new BusinessException(ErrorCode.INVALID_INPUT_VALUE);
        }

        // 섹션 검증
        section.verify();

        // 저장
        MinutesSection verifiedSection = sectionWriter.save(section);

        log.info("Section verified successfully: {}", sectionId);
        return verifiedSection;
    }

    /**
     * ID로 섹션 조회
     */
    @Override
    @Transactional(readOnly = true)
    public MinutesSection getSection(String sectionId) {
        log.debug("Getting section: {}", sectionId);

        return sectionReader.findById(sectionId)
                .orElseThrow(() -> new BusinessException(ErrorCode.ENTITY_NOT_FOUND));
    }

    /**
     * 회의록 ID로 섹션 목록 조회 (순서대로)
     */
    @Override
    @Transactional(readOnly = true)
    public List<MinutesSection> getSectionsByMinutes(String minutesId) {
        log.debug("Getting sections by minutes: {}", minutesId);

        return sectionReader.findByMinutesIdOrderByOrder(minutesId);
    }

    /**
     * 회의록 ID와 타입으로 섹션 목록 조회
     */
    @Override
    @Transactional(readOnly = true)
    public List<MinutesSection> getSectionsByMinutesAndType(String minutesId, String type) {
        log.debug("Getting sections by minutes: {} and type: {}", minutesId, type);

        return sectionReader.findByMinutesIdAndType(minutesId, type);
    }

    /**
     * 섹션 내용 수정 (WebSocket용)
     */
    @Transactional
    public MinutesSection updateSectionContent(String sectionId, String content, String userId) {
        log.info("Updating section content: {} by user: {}", sectionId, userId);

        // 섹션 조회
        MinutesSection section = sectionReader.findById(sectionId)
                .orElseThrow(() -> new BusinessException(ErrorCode.ENTITY_NOT_FOUND));

        // 잠금 상태 검증
        if (Boolean.TRUE.equals(section.getLocked())) {
            throw new BusinessException(ErrorCode.INVALID_INPUT_VALUE);
        }

        // 섹션 내용 수정
        section.update(section.getTitle(), content);

        // 저장
        MinutesSection updatedSection = sectionWriter.save(section);

        log.info("Section content updated successfully: {}", sectionId);
        return updatedSection;
    }

    /**
     * 섹션 검증 완료 (사용자 ID 포함)
     */
    @Transactional
    public MinutesSection verifySectionComplete(String sectionId, String userId) {
        log.info("Verifying section complete: {} by user: {}", sectionId, userId);

        // 권한 검증 등 추가 로직이 필요하면 여기에 구현
        return verifySection(sectionId);
    }
}
