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

"""
Vibrant风格（活力风格）海报模板
"""
import logging
import math
from typing import Dict, Any, Optional, Tuple

import numpy as np
from PIL import Image, ImageDraw, ImageFont

from .base_template import BaseTemplate
from ..utils import ColorExtractor

logger = logging.getLogger(__name__)


class VibrantTemplate(BaseTemplate):
    """
    活力风格模板，适用于色彩鲜艳、内容丰富的场景，如旅游、美食分享。
    特点是底部有毛玻璃效果的文案区域。
    """
    def __init__(self, size: Tuple[int, int] = (900, 1200)):
        super().__init__(size)
        self.config = {
            'colors': {
                'ocean_deep': [(0, 30, 80), (20, 120, 220)],
                'sunset_warm': [(255, 94, 77), (255, 154, 0)],
                'cool_mint': [(64, 224, 208), (127, 255, 212)],
                'royal_purple': [(75, 0, 130), (138, 43, 226)],
                'forest_green': [(34, 139, 34), (144, 238, 144)],
                'fire_red': [(220, 20, 60), (255, 69, 0)],
                "gray_gradient": [(128, 128, 128), (211, 211, 211)],
                "dark_gray": [(15, 15, 15), (30, 30, 30)]
            },
            'glass_effect': {
                'max_opacity': 240,
                'blur_radius': 22,
                'transition_height': 80,
                'intensity_multiplier': 1.5
            },
        }

    def generate(self,
                 image_path: str,
                 content: Optional[Dict[str, Any]] = None,
                 theme_color: Optional[str] = None,
                 glass_intensity: float = 1.5,
                 **kwargs) -> Image.Image:
        """
        生成Vibrant风格海报

        Args:
            image_path (str): 主图路径
            content (Optional[Dict[str, Any]]): 包含所有文本信息的字典
            theme_color (Optional[str]): 预设颜色主题的名称
            glass_intensity (float): 毛玻璃效果强度

        Returns:
            Image.Image: 生成的海报图像
        """
        if content is None:
            content = self._get_default_content()

        self.config['glass_effect']['intensity_multiplier'] = glass_intensity

        main_image = self.image_processor.load_image(image_path)
        if not main_image:
            logger.error(f"无法加载图片: {image_path}")
            return None

        main_image = self.image_processor.resize_and_crop(main_image, self.size)

        estimated_height = self._estimate_content_height(content)
        gradient_start = self._detect_gradient_start_position(main_image, estimated_height)

        canvas = self._create_composite_image(main_image, gradient_start, theme_color)
        canvas = self._render_texts(canvas, content, gradient_start)

        final_image = canvas.resize((1350, 1800), Image.LANCZOS)
        return final_image

    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 _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:
        """动态检测渐变起始位置"""
        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]) -> Image.Image:
        """创建毛玻璃背景和复合图像"""
        if theme_color and theme_color in self.config['colors']:
            top_color, bottom_color = self.config['colors'][theme_color]
        else:
            top_color, bottom_color = self._extract_glass_colors_from_image(main_image, gradient_start)
        
        logger.info(f"使用毛玻璃颜色: 顶部={top_color}, 底部={bottom_color}")
        
        gradient_overlay = self._create_frosted_glass_overlay(top_color, bottom_color, gradient_start)
        
        composite_img = Image.new('RGBA', self.size, (0, 0, 0, 0))
        composite_img.paste(main_image, (0, 0))
        composite_img = Image.alpha_composite(composite_img, gradient_overlay)
        
        return composite_img

    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.config['glass_effect']
        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 self.image_processor.apply_blur(overlay, radius=enhanced_blur)

    def _extract_glass_colors_from_image(self, image: Image.Image, gradient_start: int) -> tuple:
        """从图片中提取用于毛玻璃背景的颜色"""
        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:
        """渲染所有文本元素，采用双栏布局"""
        draw = ImageDraw.Draw(canvas)
        width, height = canvas.size
        center_x = width // 2

        left_margin, right_margin = self._calculate_content_margins(content, width, center_x)
        
        footer_y = height - 30
        self._render_footer(draw, content, footer_y, left_margin, right_margin)

        title_y = gradient_start + 40
        current_y = self._render_title_subtitle(draw, content, title_y, center_x, left_margin, right_margin)

        content_area_width = right_margin - left_margin
        left_column_width = int(content_area_width * 0.5)
        right_column_x = left_margin + left_column_width

        content_start_y = current_y + 30
        self._render_left_column(draw, content, content_start_y, left_margin, left_column_width, height)
        self._render_right_column(draw, content, content_start_y, right_column_x, right_margin)

        return canvas

    def _calculate_content_margins(self, content: Dict[str, Any], width: int, center_x: int) -> Tuple[int, int]:
        """计算内容区域的左右边距"""
        title_text = content.get("title", "")
        title_size, title_width = self.text_renderer.calculate_font_size_and_width(
            title_text, int(width * 0.95), max_size=130)
        title_x = center_x - title_width // 2

        slogan_text = content.get("slogan", "")
        subtitle_size, subtitle_width = self.text_renderer.calculate_font_size_and_width(
            slogan_text, int(width * 0.9), max_size=50)
        subtitle_x = center_x - subtitle_width // 2

        padding = 20
        left_margin = max(40, min(title_x, subtitle_x) - padding)
        right_margin = min(width - 40, max(title_x + title_width, subtitle_x + subtitle_width) + padding)

        if (right_margin - left_margin) < (min_width := int(width * 0.75)):
            extra = min_width - (right_margin - left_margin)
            left_margin = max(30, left_margin - extra // 2)
            right_margin = min(width - 30, right_margin + extra // 2)

        return left_margin, right_margin

    def _render_footer(self, draw: ImageDraw.Draw, content: Dict[str, Any], y: int, left: int, right: int):
        """渲染页脚文本"""
        font = self.text_renderer.load_font(18)
        if tag := content.get("tag"):
            draw.text((left, y), tag, font=font, fill=(255, 255, 255))
        if pagination := content.get("pagination"):
            width, _ = self.text_renderer.get_text_size(pagination, font)
            draw.text((right - width, y), pagination, font=font, fill=(255, 255, 255))

    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.text_renderer.calculate_font_size_and_width(title_text, title_target_width, max_size=140, min_size=40)
        title_font = self.text_renderer.load_font(title_size)
        
        text_w, text_h = self.text_renderer.get_text_size(title_text, title_font)
        title_x = center_x - text_w // 2
        
        self.text_renderer.draw_text_with_outline(draw, (title_x, y), title_text, title_font, text_color=(255, 255, 255, 255), outline_color=(0, 30, 80, 200), outline_width=4)
        
        # 副标题 (slogan)
        subtitle_text = content.get("slogan", "")
        subtitle_target_width = int((right - left) * 0.95)
        subtitle_size, _ = self.text_renderer.calculate_font_size_and_width(subtitle_text, subtitle_target_width, max_size=75, min_size=20)
        subtitle_font = self.text_renderer.load_font(subtitle_size)
        
        sub_text_w, sub_text_h = self.text_renderer.get_text_size(subtitle_text, subtitle_font)
        subtitle_x = center_x - sub_text_w // 2
        
        title_spacing = 30
        
        # 在标题下方添加装饰线
        line_y = y + text_h + 5
        line_start_x = title_x - text_w * 0.025
        line_end_x = title_x + text_w * 1.025
        draw.line([(line_start_x, line_y), (line_end_x, line_y)], fill=(215, 215, 215, 80), width=3)

        subtitle_y = y + text_h + title_spacing
        
        self.text_renderer.draw_text_with_shadow(draw, (subtitle_x, subtitle_y), subtitle_text, subtitle_font, text_color=(255, 255, 255, 255), shadow_color=(0, 0, 0, 180), shadow_offset=(2, 2))
        
        return subtitle_y + sub_text_h

    def _render_left_column(self, draw: ImageDraw.Draw, content: Dict[str, Any], y: int, x: int, width: int, canvas_height: int):
        """渲染左栏内容：按钮和项目列表"""
        button_font = self.text_renderer.load_font(30)
        button_text = content.get("content_button", "套餐内容")
        button_width, _ = self.text_renderer.get_text_size(button_text, button_font)
        button_width += 40
        button_height = 50
        self.text_renderer.draw_rounded_rectangle(draw, (x, y), (button_width, button_height), 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=button_font, fill=(255, 255, 255))

        items = content.get("content_items", [])
        if not items: return
        
        font = self.text_renderer.load_font(28)
        list_y = y + button_height + 20
        available_h = canvas_height - 30 - (len(content.get("remarks", [])) * 25 + 10) - list_y - 20
        total_items_h = len(items) * 36
        extra_space_per_item = max(0, min(17, (available_h - total_items_h) / max(1, len(items) - 1)))
        line_spacing = 8 + extra_space_per_item
        
        for i, item in enumerate(items):
            item_y = list_y + i * (28 + line_spacing)
            draw.text((x, item_y), " " + item, font=font, 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 = content.get('price', '')
        price_size, price_width = self.text_renderer.calculate_font_size_and_width(
            price_text, int((right_margin - x) * 0.7), max_size=120, min_size=40)
        price_font = self.text_renderer.load_font(price_size)

        suffix_font = self.text_renderer.load_font(int(price_size * 0.3))
        _, price_height = self.text_renderer.get_text_size(price_text, price_font)
        suffix_width, suffix_height = self.text_renderer.get_text_size("CNY起", suffix_font)
        
        price_x = right_margin - price_width - suffix_width
        self.text_renderer.draw_text_with_shadow(draw, (price_x, y), price_text, price_font)
        
        suffix_y = y + price_height - suffix_height
        draw.text((price_x + price_width, suffix_y), "CNY起", font=suffix_font, 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", "")
        ticket_size, ticket_width = self.text_renderer.calculate_font_size_and_width(
            ticket_text, int((right_margin - x) * 0.7), max_size=60, min_size=30)
        ticket_font = self.text_renderer.load_font(ticket_size)
        ticket_x = right_margin - ticket_width
        ticket_y = y + price_height + 35
        self.text_renderer.draw_text_with_shadow(draw, (ticket_x, ticket_y), ticket_text, ticket_font)
        _, ticket_height = self.text_renderer.get_text_size(ticket_text, ticket_font)

        remarks = content.get("remarks", [])
        if remarks:
            remarks_font = self.text_renderer.load_font(16)
            remarks_y = ticket_y + ticket_height + 30
            for i, remark in enumerate(remarks):
                remark_width, _ = self.text_renderer.get_text_size(remark, remarks_font)
                draw.text((right_margin - remark_width, remarks_y + i * 21), remark, font=remarks_font, fill=(255, 255, 255, 200)) 