#!/usr/bin/env python3
# -*- coding: utf-8 -*-

"""
Vibrant Template
活力风格海报模板 - 重构版本，符合原始设计规范，支持fabric.js输出
"""

import logging
import math
import json
from typing import Dict, Any, Optional, Tuple, List, Union
import numpy as np
from PIL import Image, ImageDraw, ImageFilter

from .base_template import BaseTemplate
from ....exceptions import PosterGenerationError

logger = logging.getLogger(__name__)


class VibrantTemplate(BaseTemplate):
    """
    活力风格模板 - 重构版本
    - 单图背景，毛玻璃渐变效果
    - 两栏布局（左栏内容，右栏价格）
    - 适合展示套餐内容和价格信息
    - 支持fabric.js JSON输出和透明底图
    """
    
    SUPPORTED_FEATURES = [
        "glass_effect",
        "two_column_layout", 
        "dynamic_colors",
        "text_effects",
        "fabric_json_output",
        "transparent_background"
    ]

    def __init__(self, size: Tuple[int, int] = (900, 1200), config: Optional[Dict[str, Any]] = None):
        super().__init__(size, config)
        
        # 初始化模板特定配置
        self.glass_config = self.config.get("glass_effect", {
            'max_opacity': 240,
            'blur_radius': 22,
            'transition_height': 80,
            'intensity_multiplier': 1.5
        })
        
        # 布局配置
        self.layout_config = {
            "column_divider": 0.55,  # 左栏占比
            "margins": {"left": 30, "right": 30, "top": 20, "bottom": 30},
            "content_spacing": 25,
            "button_height": 50,
            "line_spacing": 8
        }
        
        logger.debug("VibrantTemplate 初始化完成")

    def generate(
        self,
        images: List[Image.Image],
        content: Optional[Dict[str, Any]] = None,
        theme_color: Optional[str] = None,
        glass_intensity: float = 1.5,
        use_transparent_bg: bool = False,
        output_format: str = "image",  # "image", "fabric_json", "layers"
        **kwargs
    ) -> Union[Image.Image, Dict[str, Any], List[Dict[str, Any]]]:
        """
        生成Vibrant风格海报

        Args:
            images: 主图列表（如果为空且use_transparent_bg=True则创建透明底图）
            content: 包含所有文本信息的字典
            theme_color: 预设颜色主题的名称
            glass_intensity: 毛玻璃效果强度
            use_transparent_bg: 是否使用透明底图
            output_format: 输出格式 ("image", "fabric_json", "layers")
            **kwargs: 其他参数

        Returns:
            根据output_format返回不同格式的结果

        Raises:
            PosterGenerationError: 生成失败时抛出
        """
        try:
            # 使用默认内容（如果未提供）
            if content is None:
                content = self._get_default_content()

            # 验证内容格式
            if not self._validate_content(content):
                raise PosterGenerationError("内容验证失败")

            # 更新毛玻璃效果强度
            self.glass_config['intensity_multiplier'] = glass_intensity

            # 处理图像
            if not images and use_transparent_bg:
                # 创建透明底图
                main_image = self._create_transparent_background()
            elif images:
                # 验证图像
                if not self._validate_images(images):
                    raise PosterGenerationError("图像验证失败")
                main_image = self._process_main_image(images[0])
            else:
                raise PosterGenerationError("必须提供图像或启用透明底图")

            # 估算内容高度和渐变起始位置
            estimated_height = self._estimate_content_height(content)
            gradient_start = self._detect_gradient_start_position(main_image, estimated_height)

            # 根据输出格式生成不同结果
            if output_format == "fabric_json":
                return self._generate_fabric_json(main_image, content, gradient_start, theme_color, use_transparent_bg)
            elif output_format == "layers":
                return self._generate_layer_data(main_image, content, gradient_start, theme_color, use_transparent_bg)
            else:
                # 默认图像输出
                canvas = self._create_composite_image(main_image, gradient_start, theme_color, use_transparent_bg)
                canvas = self._render_texts(canvas, content, gradient_start)
                
                # 调整最终尺寸
                final_size = kwargs.get('output_size', (1350, 1800))
                final_image = canvas.resize(final_size, Image.LANCZOS)
                return final_image

        except Exception as e:
            error_msg = f"VibrantTemplate生成失败: {str(e)}"
            logger.error(error_msg, exc_info=True)
            raise PosterGenerationError(error_msg)

    def _get_default_content(self) -> Dict[str, Any]:
        """获取默认内容 - 符合原始字段结构"""
        return {
            "title": "正佳极地海洋世界",
            "slogan": "都说海洋馆是约会圣地！那锦峰夜场将是绝杀！",
            "price": "199",
            "ticket_type": "夜场票",
            "content_button": "套餐内容",
            "content_items": [
                "正佳极地海洋世界夜场票1张",
                "有效期至2025.06.02",
                "多种动物表演全部免费"
            ],
            "remarks": [
                "工作日可直接入园",
                "周末请提前1天预约"
            ],
            "tag": "#520特惠",
            "pagination": ""
        }

    def _create_transparent_background(self) -> Image.Image:
        """创建透明底图"""
        return Image.new("RGBA", self.size, (0, 0, 0, 0))

    def _process_main_image(self, image: Image.Image) -> Image.Image:
        """处理主图"""
        return self.image_processor.resize_image(
            image=image, 
            target_size=self.size,
            keep_aspect=True,
            crop=True
        )

    def _estimate_content_height(self, content: Dict[str, Any]) -> int:
        """预估内容高度 - 基于原始逻辑"""
        standard_margin = 25
        title_height = 100
        subtitle_height = 80
        button_height = 40
        
        content_items = content.get("content_items", [])
        content_line_height = 32
        content_list_height = len(content_items) * content_line_height
        
        price_height = 90
        ticket_height = 60
        
        remarks = content.get("remarks", [])
        if isinstance(remarks, str):
            remarks = [remarks]
        remarks_height = len(remarks) * 25 + 10
        
        footer_height = 40
        
        total_height = (
            20 + title_height + standard_margin + subtitle_height + standard_margin +
            button_height + 15 + content_list_height + price_height + ticket_height +
            remarks_height + footer_height + 30
        )
        return total_height

    def _detect_gradient_start_position(self, image: Image.Image, estimated_height: int) -> int:
        """动态检测渐变起始位置 - 基于原始逻辑"""
        if image.mode == "RGBA" and image.getpixel((0, 0))[3] == 0:
            # 透明底图，使用固定位置
            return max(self.height - estimated_height - 60, self.height // 2)
        
        width, height = image.size
        center_x = width // 2
        gradient_start = None
        
        # 分析图像亮度找到合适的渐变起始位置
        for y in range(height // 2, height):
            try:
                pixel = image.getpixel((center_x, y))
                if isinstance(pixel, (tuple, list)) and len(pixel) >= 3:
                    brightness = sum(pixel[:3]) / 3
                    if brightness > 50:
                        gradient_start = max(y - 20, height // 2)
                        break
            except:
                continue
        
        if gradient_start is None:
            bottom_margin = 60
            gradient_start = max(height - estimated_height - bottom_margin, height // 2)
        
        return gradient_start

    def _create_composite_image(
        self, 
        main_image: Image.Image, 
        gradient_start: int, 
        theme_color: Optional[str],
        use_transparent_bg: bool = False
    ) -> Image.Image:
        """创建合成图像"""
        
        # 创建基础画布
        if use_transparent_bg and main_image.mode == "RGBA":
            canvas = main_image.copy()
        else:
            canvas = main_image.convert("RGBA")
        
        # 获取颜色主题
        if theme_color:
            colors = self.get_color_theme(theme_color)
            top_color, bottom_color = colors[0], colors[1] if len(colors) > 1 else colors[0]
        else:
            top_color, bottom_color = self._extract_glass_colors_from_image(main_image, gradient_start)
        
        # 创建毛玻璃效果覆盖层
        glass_overlay = self._create_frosted_glass_overlay(top_color, bottom_color, gradient_start)
        
        # 应用毛玻璃效果
        canvas = Image.alpha_composite(canvas, glass_overlay)
        
        return canvas

    def _create_frosted_glass_overlay(
        self, 
        top_color: Tuple[int, int, int], 
        bottom_color: Tuple[int, int, int], 
        gradient_start: int
    ) -> Image.Image:
        """创建高级毛玻璃效果覆盖层 - 基于原始逻辑"""
        overlay = Image.new('RGBA', self.size, (0, 0, 0, 0))
        draw = ImageDraw.Draw(overlay)

        gradient_height = self.height - gradient_start
        glass_config = self.glass_config
        intensity = glass_config['intensity_multiplier']

        enhanced_opacity = min(255, int(glass_config['max_opacity'] * intensity))
        enhanced_blur = int(glass_config['blur_radius'] * intensity)

        def enhance_color(color, multiplier):
            factor = min(1.5, 1.0 + (multiplier - 1.0) * 0.3)
            return tuple(min(255, max(0, int(c * factor))) for c in color)

        top_c = enhance_color(top_color, intensity)
        bottom_c = enhance_color(bottom_color, intensity)
        top_c_arr = np.array(top_c)
        bottom_c_arr = np.array(bottom_c)

        for y in range(gradient_start, self.height):
            ratio = (y - gradient_start) / gradient_height if gradient_height > 0 else 0
            smooth_ratio = 0.5 - 0.5 * math.cos(ratio * math.pi)
            color = (1 - smooth_ratio) * top_c_arr + smooth_ratio * bottom_c_arr
            alpha_smooth = ratio ** (1.1 / intensity)
            alpha = int(enhanced_opacity * (0.02 + 0.98 * alpha_smooth))

            if (y - gradient_start) < glass_config['transition_height']:
                transition_ratio = (y - gradient_start) / glass_config['transition_height']
                alpha = int(alpha * (0.5 - 0.5 * math.cos(transition_ratio * math.pi)))

            color_tuple = tuple(int(c) for c in color) + (alpha,)
            draw.line([(0, y), (self.width, y)], fill=color_tuple)
        
        return overlay.filter(ImageFilter.GaussianBlur(radius=enhanced_blur))

    def _extract_glass_colors_from_image(self, image: Image.Image, gradient_start: int) -> tuple:
        """从图片中提取用于毛玻璃背景的颜色 - 基于原始逻辑"""
        if image.mode == "RGBA" and image.getpixel((0, 0))[3] == 0:
            # 透明底图，使用默认深色
            return (0, 30, 80), (0, 60, 120)
        
        if image.mode != 'RGB':
            image = image.convert('RGB')
        
        width, height = image.size
        top_samples, bottom_samples = [], []

        top_y = min(gradient_start + 20, height - 1)
        for x in range(0, width, 20):
            if sum(pixel := image.getpixel((x, top_y))) > 30:
                top_samples.append(pixel)
        
        bottom_y = min(height - 50, height - 1)
        for x in range(0, width, 20):
            if sum(pixel := image.getpixel((x, bottom_y))) > 30:
                bottom_samples.append(pixel)

        top_color = tuple(max(0, int(c * 0.1)) for c in np.mean(top_samples, axis=0)) if top_samples else (0, 5, 15)
        bottom_color = tuple(max(0, int(c * 0.2)) for c in np.mean(bottom_samples, axis=0)) if bottom_samples else (0, 25, 50)
        
        return top_color, bottom_color

    def _render_texts(self, canvas: Image.Image, content: Dict[str, Any], gradient_start: int) -> Image.Image:
        """渲染文本内容 - 两栏布局"""
        result = canvas.copy()
        draw = ImageDraw.Draw(result)
        
        # 布局配置
        left_margin = self.layout_config["margins"]["left"]
        right_margin = self.width - self.layout_config["margins"]["right"]
        center_x = self.width // 2
        column_divider_x = int(self.width * self.layout_config["column_divider"])
        
        current_y = gradient_start + self.layout_config["margins"]["top"]
        
        # 渲染标题和副标题（居中）
        current_y = self._render_title_subtitle(draw, content, current_y, center_x, left_margin, right_margin)
        current_y += self.layout_config["content_spacing"]
        
        # 两栏布局：左栏内容，右栏价格
        self._render_left_column(draw, content, current_y, left_margin, column_divider_x - 20, self.height)
        self._render_right_column(draw, content, current_y, column_divider_x, right_margin)
        
        # 渲染页脚信息
        self._render_footer(draw, content, right_margin)
        
        return result

    def _render_title_subtitle(self, draw: ImageDraw.Draw, content: Dict[str, Any], y: int, center_x: int, left: int, right: int) -> int:
        """渲染标题和副标题"""
        # 标题
        title_text = content.get("title", "默认标题")
        title_target_width = int((right - left) * 0.98)
        title_size = self._calculate_optimal_font_size(title_text, title_target_width, max_size=140, min_size=40)
        
        title_width, title_height = self.text_renderer.get_text_size(title_text, title_size)
        title_x = center_x - title_width // 2
        
        # 渲染标题（带轮廓）
        draw.text((title_x, y), title_text, 
                 font=self.text_renderer.get_font(title_size), fill=(255, 255, 255))
        
        # 副标题 (slogan)
        subtitle_text = content.get("slogan", "")
        if subtitle_text:
            subtitle_target_width = int((right - left) * 0.95)
            subtitle_size = self._calculate_optimal_font_size(subtitle_text, subtitle_target_width, max_size=75, min_size=20)
            
            subtitle_width, subtitle_height = self.text_renderer.get_text_size(subtitle_text, subtitle_size)
            subtitle_x = center_x - subtitle_width // 2
            
            # 在标题下方添加装饰线
            line_y = y + title_height + 5
            line_start_x = title_x - title_width * 0.025
            line_end_x = title_x + title_width * 1.025
            draw.line([(line_start_x, line_y), (line_end_x, line_y)], fill=(215, 215, 215, 80), width=3)

            subtitle_y = y + title_height + 30
            
            # 渲染副标题（带阴影）
            draw.text((subtitle_x, subtitle_y), subtitle_text,
                     font=self.text_renderer.get_font(subtitle_size), fill=(255, 255, 255))
            
            return subtitle_y + subtitle_height
        
        return y + title_height

    def _render_left_column(self, draw: ImageDraw.Draw, content: Dict[str, Any], y: int, x: int, width: int, canvas_height: int):
        """渲染左栏内容：按钮和项目列表"""
        # 内容按钮
        button_text = content.get("content_button", "套餐内容")
        button_font_size = 30
        button_width, _ = self.text_renderer.get_text_size(button_text, button_font_size)
        button_width += 40
        button_height = self.layout_config["button_height"]
        
        # 绘制按钮背景
        draw.rounded_rectangle(
            [x, y, x + button_width, y + button_height],
            radius=20,
            fill=(0, 140, 210, 180),
            outline=(255, 255, 255, 255),
            width=1
        )
        
        # 绘制按钮文字
        draw.text((x + 20, y + (button_height - 30) // 2), button_text, 
                 font=self.text_renderer.get_font(button_font_size), fill=(255, 255, 255))

        # 套餐内容列表
        items = content.get("content_items", [])
        if items:
            font_size = 28
            list_y = y + button_height + 20
            line_spacing = self.layout_config["line_spacing"]
            
            for i, item in enumerate(items):
                item_y = list_y + i * (font_size + line_spacing)
                draw.text((x, item_y), " " + item, 
                         font=self.text_renderer.get_font(font_size), fill=(255, 255, 255))

    def _render_right_column(self, draw: ImageDraw.Draw, content: Dict[str, Any], y: int, x: int, right_margin: int):
        """渲染右栏内容：价格、票种和备注"""
        # 价格
        price_text = str(content.get('price', ''))
        price_target_width = int((right_margin - x) * 0.7)
        price_size = self._calculate_optimal_font_size(price_text, price_target_width, max_size=120, min_size=40)
        
        price_width, price_height = self.text_renderer.get_text_size(price_text, price_size)
        suffix_size = int(price_size * 0.3)
        suffix_width, suffix_height = self.text_renderer.get_text_size("CNY起", suffix_size)
        
        price_x = right_margin - price_width - suffix_width
        
        # 渲染价格（带阴影）
        draw.text((price_x, y), price_text, 
                 font=self.text_renderer.get_font(price_size), fill=(255, 255, 255))
        
        # 货币后缀
        suffix_y = y + price_height - suffix_height
        draw.text((price_x + price_width, suffix_y), "CNY起", 
                 font=self.text_renderer.get_font(suffix_size), fill=(255, 255, 255))
        
        # 价格下划线
        underline_y = y + price_height + 18
        draw.line([(price_x - 10, underline_y), (right_margin, underline_y)], 
                 fill=(255, 255, 255, 80), width=2)
        
        # 票种
        ticket_text = content.get("ticket_type", "")
        if ticket_text:
            ticket_target_width = int((right_margin - x) * 0.7)
            ticket_size = self._calculate_optimal_font_size(ticket_text, ticket_target_width, max_size=60, min_size=30)
            ticket_width, ticket_height = self.text_renderer.get_text_size(ticket_text, ticket_size)
            ticket_x = right_margin - ticket_width
            ticket_y = y + price_height + 35
            
            draw.text((ticket_x, ticket_y), ticket_text, 
                     font=self.text_renderer.get_font(ticket_size), fill=(255, 255, 255))

        # 备注信息
        remarks = content.get("remarks", [])
        if remarks:
            remarks_font_size = 16
            remarks_y = ticket_y + ticket_height + 30 if ticket_text else y + price_height + 60
            
            for i, remark in enumerate(remarks):
                remark_width, _ = self.text_renderer.get_text_size(remark, remarks_font_size)
                draw.text((right_margin - remark_width, remarks_y + i * 21), remark, 
                         font=self.text_renderer.get_font(remarks_font_size), fill=(255, 255, 255, 200))

    def _render_footer(self, draw: ImageDraw.Draw, content: Dict[str, Any], right_margin: int):
        """渲染页脚信息"""
        # 标签
        tag = content.get("tag", "")
        if tag:
            tag_font_size = 18
            tag_width, tag_height = self.text_renderer.get_text_size(tag, tag_font_size)
            tag_y = self.height - 50
            draw.text((30, tag_y), tag, 
                     font=self.text_renderer.get_font(tag_font_size), fill=(255, 255, 255))
        
        # 分页信息
        pagination = content.get("pagination", "")
        if pagination:
            pagination_font_size = 16
            pagination_width, _ = self.text_renderer.get_text_size(pagination, pagination_font_size)
            pagination_y = self.height - 40
            draw.text((right_margin - pagination_width, pagination_y), pagination, 
                     font=self.text_renderer.get_font(pagination_font_size), fill=(255, 255, 255))

    def _calculate_optimal_font_size(self, text: str, target_width: int, max_size: int = 120, min_size: int = 10) -> int:
        """计算文本的最佳字体大小"""
        low = min_size
        high = max_size
        best_size = min_size
        
        while low <= high:
            mid = (low + high) // 2
            width, _ = self.text_renderer.get_text_size(text, mid)
            
            if width <= target_width:
                best_size = mid
                low = mid + 1
            else:
                high = mid - 1
        
        return best_size

    def _generate_fabric_json(
        self, 
        main_image: Image.Image, 
        content: Dict[str, Any], 
        gradient_start: int, 
        theme_color: Optional[str],
        use_transparent_bg: bool = False
    ) -> Dict[str, Any]:
        """生成Fabric.js兼容的JSON格式"""
        fabric_objects = []
        
        # 背景图层
        if not use_transparent_bg:
            fabric_objects.append({
                "type": "image",
                "version": "5.2.4",
                "originX": "left",
                "originY": "top",
                "left": 0,
                "top": 0,
                "width": self.width,
                "height": self.height,
                "scaleX": 1,
                "scaleY": 1,
                "angle": 0,
                "flipX": False,
                "flipY": False,
                "opacity": 1,
                "visible": True,
                "clipPath": None,
                "src": "data:image/png;base64,<base64_encoded_image>",  # 需要实际编码
                "name": "background"
            })
        
        # 毛玻璃效果层
        fabric_objects.append({
            "type": "rect",
            "version": "5.2.4",
            "originX": "left", 
            "originY": "top",
            "left": 0,
            "top": gradient_start,
            "width": self.width,
            "height": self.height - gradient_start,
            "fill": f"linear-gradient(90deg, rgba(0,30,80,0.6) 0%, rgba(0,60,120,0.8) 100%)",
            "opacity": 0.8,
            "visible": True,
            "name": "glass_overlay"
        })
        
        # 文本对象
        text_objects = self._generate_fabric_text_objects(content, gradient_start)
        fabric_objects.extend(text_objects)
        
        return {
            "version": "5.2.4",
            "objects": fabric_objects,
            "background": "transparent" if use_transparent_bg else "#ffffff",
            "width": self.width,
            "height": self.height
        }

    def _generate_fabric_text_objects(self, content: Dict[str, Any], gradient_start: int) -> List[Dict[str, Any]]:
        """生成Fabric.js文本对象"""
        text_objects = []
        
        # 标题
        title = content.get("title", "")
        if title:
            text_objects.append({
                "type": "text",
                "version": "5.2.4",
                "originX": "center",
                "originY": "top", 
                "left": self.width // 2,
                "top": gradient_start + 20,
                "width": 400,
                "height": 100,
                "text": title,
                "fontSize": 60,
                "fontFamily": "Arial",
                "fontWeight": "bold",
                "fill": "#ffffff",
                "stroke": "#001e50",
                "strokeWidth": 4,
                "textAlign": "center",
                "name": "title"
            })
        
        # 副标题
        slogan = content.get("slogan", "")
        if slogan:
            text_objects.append({
                "type": "text",
                "version": "5.2.4",
                "originX": "center",
                "originY": "top",
                "left": self.width // 2,
                "top": gradient_start + 120,
                "width": 500,
                "height": 80,
                "text": slogan,
                "fontSize": 32,
                "fontFamily": "Arial",
                "fill": "#ffffff",
                "textAlign": "center",
                "shadow": {
                    "color": "rgba(0,0,0,0.7)",
                    "offsetX": 2,
                    "offsetY": 2,
                    "blur": 4
                },
                "name": "slogan"
            })
        
        # 价格
        price = content.get("price", "")
        if price:
            text_objects.append({
                "type": "text",
                "version": "5.2.4",
                "originX": "right",
                "originY": "top",
                "left": self.width - 50,
                "top": gradient_start + 220,
                "width": 200,
                "height": 100,
                "text": price,
                "fontSize": 80,
                "fontFamily": "Arial",
                "fontWeight": "bold",
                "fill": "#ffffff",
                "textAlign": "right",
                "name": "price"
            })
        
        # 更多文本对象可以继续添加...
        
        return text_objects

    def _generate_layer_data(
        self, 
        main_image: Image.Image, 
        content: Dict[str, Any], 
        gradient_start: int, 
        theme_color: Optional[str],
        use_transparent_bg: bool = False
    ) -> List[Dict[str, Any]]:
        """生成分层数据（替代PSD）"""
        layers = []
        
        # 背景层
        if not use_transparent_bg:
            layers.append({
                "name": "Background Image",
                "type": "image",
                "data": main_image,
                "opacity": 1.0,
                "blend_mode": "normal",
                "visible": True
            })
        
        # 毛玻璃效果层
        glass_overlay = self._create_frosted_glass_overlay(
            *self._extract_glass_colors_from_image(main_image, gradient_start), 
            gradient_start
        )
        layers.append({
            "name": "Glass Overlay",
            "type": "overlay",
            "data": glass_overlay,
            "opacity": 0.8,
            "blend_mode": "normal",
            "visible": True
        })
        
        # 分离的文本层
        text_layers = self._create_separate_text_layers(content, gradient_start)
        layers.extend(text_layers)
        
        return layers

    def _create_separate_text_layers(self, content: Dict[str, Any], gradient_start: int) -> List[Dict[str, Any]]:
        """创建分离的文本层"""
        layers = []
        
        # 每个文本元素创建单独的层
        text_elements = [
            ("title", content.get("title", "")),
            ("slogan", content.get("slogan", "")),
            ("price", content.get("price", "")),
            ("ticket_type", content.get("ticket_type", "")),
            ("content_button", content.get("content_button", "")),
        ]
        
        for name, text in text_elements:
            if text:
                text_layer = Image.new("RGBA", self.size, (0, 0, 0, 0))
                # 这里需要渲染具体的文本到图层
                layers.append({
                    "name": f"Text_{name}",
                    "type": "text",
                    "data": text_layer,
                    "text_content": text,
                    "opacity": 1.0,
                    "blend_mode": "normal",
                    "visible": True
                })
        
        return layers

    def _validate_content(self, content: Dict[str, Any]) -> bool:
        """验证内容格式 - 基于新的字段结构"""
        required_fields = ["title", "price", "ticket_type", "content_items"]
        
        for field in required_fields:
            if field not in content or not content[field]:
                logger.error(f"内容缺少必需字段: {field}")
                return False
        
        # 验证content_items是列表
        if not isinstance(content.get("content_items"), list):
            logger.error("content_items必须是列表")
            return False
        
        return True 