from rest_framework import serializers

import logging

from apps.books.models import Book, BookChapter, EBook, ReadingProgress, ReadingStatus, DownloadRecord
from apps.books.services.metadata import enrich_ebook_metadata
from apps.books.services.process_ebook import apply_processing_to_ebook
from apps.reader.models import ReadingSettings

logger = logging.getLogger(__name__)

class BookReadingSettingsSerializer(serializers.ModelSerializer):
    font_style = serializers.CharField(source="font_family")

    class Meta:
        model = ReadingSettings
        fields = ["font_size", "font_style", "background_color"]

    def validate_font_size(self, value: int) -> int:
        if value < 12 or value > 36:
            raise serializers.ValidationError("Font size must be between 12 and 36.")
        return value


class BookChapterSerializer(serializers.ModelSerializer):
    class Meta:
        model = BookChapter
        fields = ["id", "title", "index", "href", "children"]


class EBookContentSerializer(serializers.Serializer):
    page = serializers.IntegerField()
    total_pages = serializers.IntegerField()
    content = serializers.CharField()
    chapter_title = serializers.CharField()
    format = serializers.CharField()


class EBookTocSerializer(serializers.Serializer):
    chapters = serializers.ListField(child=BookChapterSerializer())
    format = serializers.CharField()
    page_count = serializers.IntegerField()


class BookListSerializer(serializers.ModelSerializer):
    reading_status_display = serializers.CharField(source="get_reading_status_display", read_only=True)

    class Meta:
        model = Book
        fields = ["id", "title", "author", "genre", "reading_status", "reading_status_display", "cover_image"]


class BookDetailSerializer(serializers.ModelSerializer):
    reading_status_display = serializers.CharField(source="get_reading_status_display", read_only=True)

    class Meta:
        model = Book
        fields = ["id", "title", "author", "genre", "description", "reading_status", "reading_status_display", "cover_image", "total_pages", "created_at", "updated_at"]
        read_only_fields = ["id", "created_at", "updated_at"]


class BookSerializer(serializers.ModelSerializer):
    class Meta:
        model = Book
        fields = ["id", "title", "author", "genre", "description", "reading_status", "cover_image", "total_pages", "created_at", "updated_at"]
        read_only_fields = ["id", "created_at", "updated_at"]


class EBookListSerializer(serializers.ModelSerializer):
    filename = serializers.CharField(read_only=True)
    format = serializers.CharField(read_only=True)
    progress = serializers.SerializerMethodField()
    started = serializers.SerializerMethodField()

    class Meta:
        model = EBook
        fields = [
            "id", "title", "author", "filename", "format", "page_count", "file_size",
            "cover_image", "created_at", "progress", "started",
        ]

    def get_progress(self, obj):
        try:
            return obj.reading_progress.current_position
        except ReadingProgress.DoesNotExist:
            return None

    def get_started(self, obj):
        """True when the user has opened the reader and has a saved EPUB location."""
        try:
            rp = obj.reading_progress
        except ReadingProgress.DoesNotExist:
            return False
        if rp.current_position >= 99:
            return False
        return bool((rp.epub_location or "").strip())


class EBookDetailSerializer(serializers.ModelSerializer):
    filename = serializers.CharField(read_only=True)
    format = serializers.CharField(read_only=True)
    file_url = serializers.SerializerMethodField()
    progress = serializers.SerializerMethodField()
    metadata = serializers.JSONField(source="metadata_json", read_only=True)

    class Meta:
        model = EBook
        fields = [
            "id", "title", "author", "filename", "format", "page_count", "file_size",
            "file_url", "cover_image", "metadata", "created_at", "updated_at", "progress",
        ]

    def get_file_url(self, obj):
        request = self.context.get("request")
        if request and obj.file:
            return request.build_absolute_uri(obj.file.url)
        return ""

    def get_progress(self, obj):
        try:
            rp = obj.reading_progress
            return {
                "current_position": rp.current_position,
                "last_page": rp.last_page,
                "epub_location": rp.epub_location,
            }
        except ReadingProgress.DoesNotExist:
            return None


class EBookUploadSerializer(serializers.ModelSerializer):
    class Meta:
        model = EBook
        fields = ["title", "author", "file", "cover_image"]
        extra_kwargs = {"title": {"required": True}, "file": {"required": True}}

    def validate_file(self, value):
        import os
        if value is None:
            return value
        ext = os.path.splitext(str(getattr(value, "name", "")))[1].lower()
        if ext not in (".epub", ".pdf"):
            raise serializers.ValidationError("Only EPUB and PDF files are supported.")
        return value

    def create(self, validated_data):
        import os

        validated_data["user"] = self.context["request"].user
        name = str(getattr(validated_data.get("file"), "name", ""))
        ext = os.path.splitext(name)[1].lower().lstrip(".")
        if ext:
            validated_data["format"] = ext
        ebook = super().create(validated_data)
        try:
            apply_processing_to_ebook(ebook)
        except Exception:
            logger.exception("E-book processing failed for ebook %s", ebook.pk)
        try:
            enrich_ebook_metadata(ebook)
        except Exception:
            logger.exception("Metadata enrichment failed for ebook %s", ebook.pk)
        ebook.refresh_from_db()
        return ebook


class ReadingProgressSerializer(serializers.ModelSerializer):
    class Meta:
        model = ReadingProgress
        fields = [
            "current_position", "last_page", "epub_location",
            "device_id", "device_name", "version", "updated_at",
        ]
        read_only_fields = ["version", "updated_at"]
        extra_kwargs = {"current_position": {"required": False, "min_value": 0.0, "max_value": 100.0}}

    def validate_current_position(self, value):
        if value < 0.0 or value > 100.0:
            raise serializers.ValidationError("Position must be between 0.0 and 100.0.")
        return value


class DownloadRecordSerializer(serializers.ModelSerializer):
    ebook_id = serializers.IntegerField(source="ebook.id", read_only=True)
    ebook_title = serializers.CharField(source="ebook.title", read_only=True)
    author = serializers.CharField(source="ebook.author", read_only=True)
    filename = serializers.SerializerMethodField()
    cover_image = serializers.ImageField(source="ebook.cover_image", read_only=True)
    format = serializers.CharField(source="ebook.format", read_only=True)
    progress = serializers.SerializerMethodField()
    file_url = serializers.SerializerMethodField()

    class Meta:
        model = DownloadRecord
        fields = [
            "id", "ebook_id", "ebook_title", "author", "filename", "file_url",
            "file_size", "cover_image", "format", "downloaded_at", "progress",
        ]

    def get_filename(self, obj):
        return obj.ebook.filename()

    def get_file_url(self, obj):
        request = self.context.get("request")
        if request and obj.ebook.file:
            return request.build_absolute_uri(obj.ebook.file.url)
        return ""

    def get_progress(self, obj):
        try:
            rp = obj.ebook.reading_progress
            return {
                "current_position": rp.current_position,
                "last_page": rp.last_page,
                "epub_location": rp.epub_location,
            }
        except ReadingProgress.DoesNotExist:
            return None


class StorageSummarySerializer(serializers.Serializer):
    total_downloads = serializers.IntegerField()
    total_size_bytes = serializers.IntegerField()
    ebooks = serializers.ListField(child=serializers.DictField())