"""
故事模块视图 - App端
"""
from django.db import transaction
from django.db.models import Count
from django.http import StreamingHttpResponse
from rest_framework import viewsets
from rest_framework.decorators import action
from rest_framework.permissions import IsAuthenticated
from drf_spectacular.utils import extend_schema

from utils.response import success, error
from utils.exceptions import ErrorCode
from apps.admins.authentication import AppJWTAuthentication
from .models import StoryShelf, Story
from .utils import ensure_default_stories
from .serializers import (
    StoryShelfSerializer,
    CreateShelfSerializer,
    StoryListSerializer,
    StoryDetailSerializer,
    CreateStorySerializer,
    GenerateStorySerializer,
)


def ensure_default_shelf(user):
    """确保用户有默认书架，没有则创建"""
    if not StoryShelf.objects.filter(user=user).exists():
        StoryShelf.objects.create(user=user, name='我的书架')


@extend_schema(tags=['故事'])
class StoryViewSet(viewsets.ViewSet):
    """故事视图集（App端）"""

    authentication_classes = [AppJWTAuthentication]
    permission_classes = [IsAuthenticated]

    def list(self, request):
        """
        获取故事列表
        GET /api/v1/stories/?shelf_id=1&page=1&page_size=20
        """
        ensure_default_stories(request.user)
        queryset = Story.objects.filter(user=request.user)

        shelf_id = request.query_params.get('shelf_id')
        if shelf_id:
            queryset = queryset.filter(shelf_id=shelf_id)

        # 分页
        page = int(request.query_params.get('page', 1))
        page_size = int(request.query_params.get('page_size', 20))
        start = (page - 1) * page_size
        total = queryset.count()
        items = queryset[start:start + page_size]

        return success(data={
            'total': total,
            'items': StoryListSerializer(items, many=True).data,
        })

    def create(self, request):
        """
        保存故事
        POST /api/v1/stories/
        """
        serializer = CreateStorySerializer(data=request.data)
        if not serializer.is_valid():
            return error(message=str(serializer.errors))

        shelf_id = serializer.validated_data['shelf_id']
        try:
            shelf = StoryShelf.objects.get(
                id=shelf_id, user=request.user, is_locked=False
            )
        except StoryShelf.DoesNotExist:
            return error(code=ErrorCode.SHELF_NOT_FOUND, message='书架不存在或未解锁')

        if shelf.is_full:
            return error(code=ErrorCode.SHELF_FULL, message='书架已满，请解锁新书架')

        story = Story.objects.create(
            user=request.user,
            shelf=shelf,
            title=serializer.validated_data['title'],
            content=serializer.validated_data['content'],
            cover_url=serializer.validated_data.get('cover_url', ''),
            generation_mode=serializer.validated_data.get('generation_mode', 'ai'),
            prompt=serializer.validated_data.get('prompt', ''),
        )

        return success(
            data=StoryDetailSerializer(story).data,
            message='保存成功'
        )

    def destroy(self, request, pk=None):
        """
        删除故事
        DELETE /api/v1/stories/{id}/
        """
        try:
            story = Story.objects.get(id=pk, user=request.user)
        except Story.DoesNotExist:
            return error(code=ErrorCode.STORY_NOT_FOUND, message='故事不存在')
        story.delete()
        return success(message='删除成功')

    @action(detail=False, methods=['post'], url_path='generate')
    def generate(self, request):
        """
        生成故事 (SSE 流式)
        POST /api/v1/stories/generate/
        """
        serializer = GenerateStorySerializer(data=request.data)
        if not serializer.is_valid():
            return error(message=str(serializer.errors))

        characters = serializer.validated_data.get('characters', [])
        scenes = serializer.validated_data.get('scenes', [])
        props = serializer.validated_data.get('props', [])

        from .services.llm_service import generate_story_stream

        response = StreamingHttpResponse(
            generate_story_stream(characters, scenes, props),
            content_type='text/event-stream',
        )
        response['Cache-Control'] = 'no-cache'
        response['X-Accel-Buffering'] = 'no'
        return response

    @action(detail=True, methods=['get', 'post'], url_path='tts')
    def tts(self, request, pk=None):
        """
        TTS 音频接口
        GET  /api/v1/stories/{id}/tts/ - 查询音频状态
        POST /api/v1/stories/{id}/tts/ - 生成 TTS 音频 (SSE 流式)
        """
        try:
            story = Story.objects.get(id=pk, user=request.user)
        except Story.DoesNotExist:
            return error(code=ErrorCode.STORY_NOT_FOUND, message='故事不存在')

        if request.method == 'GET':
            return success(data={
                'exists': bool(story.audio_url),
                'audio_url': story.audio_url,
            })

        # POST: 生成音频
        from .services.tts_service import generate_tts_stream

        response = StreamingHttpResponse(
            generate_tts_stream(story),
            content_type='text/event-stream',
        )
        response['Cache-Control'] = 'no-cache'
        response['X-Accel-Buffering'] = 'no'
        return response


@extend_schema(tags=['故事'])
class ShelfViewSet(viewsets.ViewSet):
    """书架视图集（App端）"""

    authentication_classes = [AppJWTAuthentication]
    permission_classes = [IsAuthenticated]

    def list(self, request):
        """
        书架列表
        GET /api/v1/stories/shelves/
        """
        ensure_default_stories(request.user)

        shelves = StoryShelf.objects.filter(
            user=request.user
        ).annotate(story_count=Count('stories'))
        return success(data=StoryShelfSerializer(shelves, many=True).data)

    def create(self, request):
        """
        创建书架
        POST /api/v1/stories/shelves/
        """
        serializer = CreateShelfSerializer(data=request.data)
        if not serializer.is_valid():
            return error(message=str(serializer.errors))

        shelf = StoryShelf.objects.create(
            user=request.user,
            name=serializer.validated_data['name'],
        )
        return success(data=StoryShelfSerializer(shelf).data, message='创建成功')

    def destroy(self, request, pk=None):
        """
        删除书架（故事保留，shelf_id 置 null）
        DELETE /api/v1/stories/shelves/{id}/
        """
        try:
            shelf = StoryShelf.objects.get(id=pk, user=request.user)
        except StoryShelf.DoesNotExist:
            return error(code=ErrorCode.SHELF_NOT_FOUND, message='书架不存在')

        with transaction.atomic():
            try:
                Story.objects.filter(shelf=shelf).update(shelf=None)
            except Exception:
                Story.objects.filter(shelf=shelf).delete()
            shelf.delete()
        return success(message='删除成功')

    @action(detail=False, methods=['post'], url_path='unlock')
    def unlock(self, request):
        """
        积分解锁新书架
        POST /api/v1/stories/shelves/unlock/
        """
        from apps.users.models import PointsRecord

        # 解锁费用（可后续改为从配置读取）
        unlock_cost = 100
        user = request.user

        if user.points < unlock_cost:
            return error(
                code=ErrorCode.POINTS_NOT_ENOUGH,
                message=f'积分不足，需要 {unlock_cost} 积分，当前 {user.points} 积分'
            )

        shelf_count = StoryShelf.objects.filter(user=user).count()
        shelf_name = f'书架 {shelf_count + 1}'

        with transaction.atomic():
            # 扣除积分
            user.points -= unlock_cost
            user.save(update_fields=['points'])

            # 创建书架
            shelf = StoryShelf.objects.create(
                user=user,
                name=shelf_name,
                unlock_cost=unlock_cost,
            )

            # 记录积分流水
            PointsRecord.objects.create(
                user=user,
                amount=-unlock_cost,
                type='unlock_shelf',
                description=f'解锁书架「{shelf_name}」',
            )

        shelf.story_count = 0
        return success(data={
            'shelf': StoryShelfSerializer(shelf).data,
            'remaining_points': user.points,
        }, message='解锁成功')
