"""
Todo 비즈니스 로직 서비스
- 서비스 클래스 기준: 최대 350줄
- 간결함 원칙: 핵심 Todo 로직만 포함
"""
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import select, func, and_
from typing import List, Optional
from datetime import datetime
from uuid import UUID
import logging

from ..models.user import User
from ..models.todo import TodoItem, TodoComment
from ..schemas.todo import (
    TodoItemCreate, TodoItemSchedule, TodoItemSplit, TodoItemDelay,
    TodoItemResponse, TodoCommentCreate, TodoCommentResponse
)

logger = logging.getLogger(__name__)


class TodoService:
    """Todo 관련 비즈니스 로직 서비스"""
    
    def __init__(self, db: AsyncSession):
        self.db = db
    
    async def create_todo(self, todo_data: TodoItemCreate, user_id: UUID) -> TodoItemResponse:
        """새 할일 생성"""
        new_todo = TodoItem(
            user_id=user_id,
            content=todo_data.content,
            status="draft"
        )
        
        self.db.add(new_todo)
        await self.db.commit()
        await self.db.refresh(new_todo)
        
        return await self._build_todo_response(new_todo)
    
    async def schedule_todo(
        self, 
        todo_id: UUID, 
        schedule_data: TodoItemSchedule, 
        user_id: UUID
    ) -> TodoItemResponse:
        """할일 일정 설정"""
        todo_item = await self._get_user_todo(todo_id, user_id, "draft")
        
        # 2시간 이상인 경우 분할 제안
        if schedule_data.estimated_minutes > 120:
            raise ValueError("Tasks longer than 2 hours should be split")
        
        todo_item.start_date = schedule_data.start_date
        todo_item.estimated_minutes = schedule_data.estimated_minutes
        todo_item.status = "scheduled"
        
        await self.db.commit()
        await self.db.refresh(todo_item)
        
        return await self._build_todo_response(todo_item)
    
    async def complete_todo(self, todo_id: UUID, user_id: UUID) -> TodoItemResponse:
        """할일 완료"""
        todo_item = await self._get_user_todo(todo_id, user_id, "active")
        
        todo_item.status = "completed"
        todo_item.completed_at = datetime.utcnow()
        
        await self.db.commit()
        await self.db.refresh(todo_item)
        
        return await self._build_todo_response(todo_item)
    
    async def delay_todo(
        self, 
        todo_id: UUID, 
        delay_data: TodoItemDelay, 
        user_id: UUID
    ) -> TodoItemResponse:
        """할일 지연"""
        todo_item = await self._get_user_todo(todo_id, user_id, "active")
        
        todo_item.status = "delayed"
        todo_item.delayed_until = delay_data.delayed_until
        todo_item.start_date = delay_data.delayed_until
        
        await self.db.commit()
        await self.db.refresh(todo_item)
        
        return await self._build_todo_response(todo_item)
    
    async def split_todo(
        self, 
        todo_id: UUID, 
        split_data: TodoItemSplit, 
        user_id: UUID
    ) -> List[TodoItemResponse]:
        """할일 분할"""
        original_todo = await self._get_user_todo(todo_id, user_id, "draft")
        
        # 분할된 할일들 생성
        subtasks = []
        for i, (content, minutes) in enumerate(zip(split_data.subtasks, split_data.estimated_minutes_per_task)):
            if minutes > 120:
                raise ValueError(f"Subtask {i+1} is longer than 2 hours")
            
            subtask = TodoItem(
                user_id=user_id,
                content=content,
                status="draft",
                parent_id=original_todo.id,
                split_order=i + 1
            )
            self.db.add(subtask)
            subtasks.append(subtask)
        
        original_todo.status = "split"
        await self.db.commit()
        
        # 응답 데이터 구성
        response_data = []
        for subtask in subtasks:
            await self.db.refresh(subtask)
            response_data.append(await self._build_todo_response(subtask))
        
        return response_data
    
    async def get_todos(
        self, 
        user_id: UUID, 
        status_filter: Optional[str] = None
    ) -> List[TodoItemResponse]:
        """할일 목록 조회"""
        query = select(TodoItem).where(TodoItem.user_id == user_id)
        
        if status_filter:
            query = query.where(TodoItem.status == status_filter)
        
        query = query.order_by(TodoItem.created_at.desc())
        
        result = await self.db.execute(query)
        todo_items = result.scalars().all()
        
        response_data = []
        for todo_item in todo_items:
            response_data.append(await self._build_todo_response(todo_item))
        
        return response_data
    
    async def get_active_todos(self, user_id: UUID) -> List[TodoItemResponse]:
        """활성 할일 조회 (scheduled → active 자동 변환 포함)"""
        now = datetime.utcnow()
        
        # scheduled → active 자동 변환
        update_result = await self.db.execute(
            select(TodoItem).where(
                and_(
                    TodoItem.user_id == user_id,
                    TodoItem.status == "scheduled",
                    TodoItem.start_date <= now
                )
            )
        )
        scheduled_items = update_result.scalars().all()
        
        for item in scheduled_items:
            item.status = "active"
        
        if scheduled_items:
            await self.db.commit()
        
        # active 할일들 조회
        result = await self.db.execute(
            select(TodoItem).where(
                and_(
                    TodoItem.user_id == user_id,
                    TodoItem.status == "active"
                )
            ).order_by(TodoItem.start_date.asc())
        )
        active_todos = result.scalars().all()
        
        response_data = []
        for todo_item in active_todos:
            response_data.append(await self._build_todo_response(todo_item))
        
        return response_data
    
    async def create_comment(
        self, 
        todo_id: UUID, 
        comment_data: TodoCommentCreate, 
        user_id: UUID
    ) -> TodoCommentResponse:
        """댓글 생성"""
        # 할일 존재 확인
        await self._get_user_todo(todo_id, user_id)
        
        new_comment = TodoComment(
            todo_item_id=todo_id,
            user_id=user_id,
            content=comment_data.content
        )
        
        self.db.add(new_comment)
        await self.db.commit()
        await self.db.refresh(new_comment)
        
        return TodoCommentResponse(
            id=new_comment.id,
            todo_item_id=new_comment.todo_item_id,
            user_id=new_comment.user_id,
            content=new_comment.content,
            created_at=new_comment.created_at,
            updated_at=new_comment.updated_at
        )
    
    async def get_comments(self, todo_id: UUID, user_id: UUID) -> List[TodoCommentResponse]:
        """댓글 목록 조회"""
        # 할일 존재 확인
        await self._get_user_todo(todo_id, user_id)
        
        result = await self.db.execute(
            select(TodoComment).where(TodoComment.todo_item_id == todo_id)
            .order_by(TodoComment.created_at.asc())
        )
        comments = result.scalars().all()
        
        return [
            TodoCommentResponse(
                id=comment.id,
                todo_item_id=comment.todo_item_id,
                user_id=comment.user_id,
                content=comment.content,
                created_at=comment.created_at,
                updated_at=comment.updated_at
            )
            for comment in comments
        ]
    
    # ========================================================================
    # 헬퍼 메서드들
    # ========================================================================
    
    async def _get_user_todo(
        self, 
        todo_id: UUID, 
        user_id: UUID, 
        required_status: Optional[str] = None
    ) -> TodoItem:
        """사용자의 할일 조회"""
        query = select(TodoItem).where(
            and_(
                TodoItem.id == todo_id,
                TodoItem.user_id == user_id
            )
        )
        
        if required_status:
            query = query.where(TodoItem.status == required_status)
        
        result = await self.db.execute(query)
        todo_item = result.scalar_one_or_none()
        
        if not todo_item:
            detail = "Todo item not found"
            if required_status:
                detail += f" or not in {required_status} status"
            raise ValueError(detail)
        
        return todo_item
    
    async def _get_comment_count(self, todo_id: UUID) -> int:
        """댓글 수 조회"""
        result = await self.db.execute(
            select(func.count(TodoComment.id)).where(TodoComment.todo_item_id == todo_id)
        )
        return result.scalar() or 0
    
    async def _build_todo_response(self, todo_item: TodoItem) -> TodoItemResponse:
        """TodoItem을 TodoItemResponse로 변환"""
        comment_count = await self._get_comment_count(todo_item.id)
        
        return TodoItemResponse(
            id=todo_item.id,
            user_id=todo_item.user_id,
            content=todo_item.content,
            status=todo_item.status,
            created_at=todo_item.created_at,
            start_date=todo_item.start_date,
            estimated_minutes=todo_item.estimated_minutes,
            completed_at=todo_item.completed_at,
            delayed_until=todo_item.delayed_until,
            parent_id=todo_item.parent_id,
            split_order=todo_item.split_order,
            comment_count=comment_count
        )
