"""
月次レポート生成サービス - HTML/PDF生成
"""
import os
import sys
from datetime import datetime
from jinja2 import Environment, FileSystemLoader

# パスを追加
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))


class MonthlyReportHTML:
    """月次レポートHTML/PDF生成クラス"""

    def __init__(self, data: dict, analyses: dict = None):
        """
        Args:
            data: ReportDataAggregator.collect_all_data()の戻り値
            analyses: LLMAnalyzer.analyze_all()の戻り値（オプション）
        """
        self.data = data
        self.analyses = analyses or {}

        # Jinja2環境のセットアップ
        template_dir = os.path.join(
            os.path.dirname(os.path.dirname(os.path.abspath(__file__))),
            'templates'
        )
        self.env = Environment(
            loader=FileSystemLoader(template_dir),
            autoescape=True
        )
        # カスタムフィルター追加
        self.env.filters['tojson'] = self._tojson_filter

    def _tojson_filter(self, value):
        """Jinja2用のJSONフィルター"""
        import json

        def json_serializer(obj):
            if hasattr(obj, 'isoformat'):
                return obj.isoformat()
            if hasattr(obj, '__dict__'):
                return obj.__dict__
            return str(obj)

        return json.dumps(value, ensure_ascii=False, default=json_serializer)

    def _prepare_template_data(self, standalone: bool = False) -> dict:
        """テンプレートに渡すデータを準備"""
        # ヒートマップデータの処理
        raw_hour_by_dow = self.data.get('hour_by_day_of_week', [])

        # リスト形式を辞書形式に変換
        # [{'day_of_week': 0, 'hour': 9, 'count': 5}, ...] -> {0: {9: 5, ...}, ...}
        hour_by_dow = {}
        max_count = 0

        if isinstance(raw_hour_by_dow, list):
            for item in raw_hour_by_dow:
                day = item.get('day_of_week', 0)
                hour = item.get('hour', 0)
                count = item.get('count', 0)
                if day not in hour_by_dow:
                    hour_by_dow[day] = {}
                hour_by_dow[day][hour] = count
                if count > max_count:
                    max_count = count
        elif isinstance(raw_hour_by_dow, dict):
            hour_by_dow = raw_hour_by_dow
            for day_data in hour_by_dow.values():
                if isinstance(day_data, dict):
                    for count in day_data.values():
                        if count > max_count:
                            max_count = count

        template_data = {
            'period': self.data['period'],
            'summary': self.data['summary'],
            'comparison': self.data['comparison'],
            'daily_stats': self.data['daily_stats'],
            'hourly_stats': self.data['hourly_stats'],
            'day_of_week_stats': self.data['day_of_week_stats'],
            'hour_by_day_of_week': hour_by_dow,
            'hour_by_day_of_week_max': max_count,
            'avg_turns': self.data['avg_turns'],
            'keywords': self.data.get('keywords', []),
            'unresolved_keywords': self.data.get('unresolved_keywords', []),
            'unanswered_questions': self.data.get('unanswered_questions', []),
            'recent_disliked': self.data.get('recent_disliked', []),
            'feedback_daily_stats': self.data.get('feedback_daily_stats', []),
            'qa_usage_ranking': self.data.get('qa_usage_ranking', []),
            'category_usage_ranking': self.data.get('category_usage_ranking', []),
            'estimated_savings': self.data['estimated_savings'],
            'analyses': self.analyses,
            'generated_at': datetime.now().strftime('%Y年%m月%d日 %H:%M'),
        }

        # スタンドアロン版の場合、CSSとJSをインライン化
        if standalone:
            base_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
            css_path = os.path.join(base_dir, 'static', 'css', 'report.css')
            js_path = os.path.join(base_dir, 'static', 'js', 'charts.js')

            css_content = ''
            if os.path.exists(css_path):
                with open(css_path, 'r', encoding='utf-8') as f:
                    css_content = f.read()

            js_content = ''
            if os.path.exists(js_path):
                with open(js_path, 'r', encoding='utf-8') as f:
                    js_content = f.read()

            template_data['css_content'] = css_content
            template_data['js_content'] = js_content

        return template_data

    def generate_html(self, output_path: str = None, standalone: bool = True) -> str:
        """
        HTMLを生成

        Args:
            output_path: 出力ファイルパス（Noneの場合はHTML文字列のみ返す）
            standalone: Trueの場合、CSS/JSをインライン化してスタンドアロンHTMLを生成

        Returns:
            生成されたHTML文字列
        """
        # スタンドアロン版はCSSとJSをインライン化
        if standalone:
            template = self.env.get_template('report_standalone.html')
        else:
            template = self.env.get_template('report.html')

        template_data = self._prepare_template_data(standalone=standalone)
        html = template.render(**template_data)

        if output_path:
            # 出力ディレクトリを作成
            output_dir = os.path.dirname(output_path)
            if output_dir:
                os.makedirs(output_dir, exist_ok=True)

            with open(output_path, 'w', encoding='utf-8') as f:
                f.write(html)
            print(f"HTML出力: {output_path}")

        return html

    def generate_pdf(self, output_path: str) -> str:
        """
        PDFを生成（HTML→PDF変換、グラフ画像埋め込み）

        Args:
            output_path: 出力ファイルパス

        Returns:
            出力ファイルパス
        """
        try:
            from weasyprint import HTML, CSS
        except ImportError:
            raise ImportError(
                "weasyprintがインストールされていません。\n"
                "pip install weasyprint でインストールしてください。\n"
                "Windowsの場合はGTKのインストールも必要です。"
            )

        # matplotlibでグラフ画像を生成
        chart_images = {}
        try:
            from .pdf_charts import generate_all_charts
            chart_images = generate_all_charts(self.data)
            print("グラフ画像を生成しました")
        except ImportError as e:
            print(f"警告: matplotlibが見つかりません。グラフなしでPDF生成します: {e}")
        except Exception as e:
            print(f"警告: グラフ生成に失敗しました: {e}")

        # HTMLを生成
        html_content = self.generate_html()

        # グラフ画像をHTMLに埋め込む
        if chart_images:
            html_content = self._embed_chart_images(html_content, chart_images)

        # 出力ディレクトリを作成
        os.makedirs(os.path.dirname(output_path), exist_ok=True)

        # CSSファイルのパスを取得
        base_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
        css_path = os.path.join(base_dir, 'static', 'css', 'report.css')

        # PDF用の追加CSS
        pdf_css = CSS(string='''
            @font-face {
                font-family: 'NotoSansCJKJP';
                src: url('/usr/share/fonts/opentype/noto/NotoSansCJK-Regular.ttc');
                font-weight: normal;
            }
            @font-face {
                font-family: 'NotoSansCJKJP';
                src: url('/usr/share/fonts/opentype/noto/NotoSansCJK-Bold.ttc');
                font-weight: bold;
            }
            @page {
                size: A4;
                margin: 15mm;
            }
            body {
                background: white;
                font-family: 'NotoSansCJKJP', sans-serif;
            }
            .report-container {
                max-width: none;
            }
            .page {
                box-shadow: none;
                margin-bottom: 0;
                page-break-after: always;
            }
            .page:last-child {
                page-break-after: auto;
            }
            /* Chart.jsのcanvasは非表示、代わりにimg.chart-imageを表示 */
            canvas {
                display: none;
            }
            .chart-container {
                min-height: auto;
                background: transparent;
            }
            .chart-image {
                max-width: 100%;
                height: auto;
            }
            /* グラフ画像がない場合のフォールバック */
            .chart-container:not(:has(img))::after {
                content: "グラフはHTMLプレビューで確認してください";
                font-size: 10pt;
                color: #999;
            }
        ''')

        # HTML→PDF変換
        html_doc = HTML(string=html_content, base_url=base_dir)

        stylesheets = [pdf_css]
        if os.path.exists(css_path):
            stylesheets.insert(0, CSS(filename=css_path))

        html_doc.write_pdf(output_path, stylesheets=stylesheets)
        print(f"PDF出力: {output_path}")

        return output_path

    def _embed_chart_images(self, html_content: str, chart_images: dict) -> str:
        """
        HTMLにグラフ画像を埋め込む

        Args:
            html_content: 元のHTML
            chart_images: グラフ画像の辞書 {chart_id: base64_image}

        Returns:
            画像埋め込み済みHTML
        """
        import re

        # 各グラフのcanvas要素をimg要素に置換
        replacements = {
            'dailyChart': chart_images.get('daily'),
            'comparisonChart': chart_images.get('comparison'),
            'hourlyChart': chart_images.get('hourly'),
            'dayOfWeekChart': chart_images.get('day_of_week'),
            'resolutionPieChart': chart_images.get('resolution_pie'),
            'keywordsChart': chart_images.get('keywords'),
            'unresolvedKeywordsChart': chart_images.get('unresolved_keywords'),
            'categoryRankingChart': chart_images.get('category_ranking'),
        }

        for canvas_id, img_data in replacements.items():
            if img_data:
                # canvas要素をimg要素に置換
                pattern = f'<canvas id="{canvas_id}"[^>]*></canvas>'
                replacement = f'<img src="{img_data}" class="chart-image" alt="{canvas_id}">'
                html_content = re.sub(pattern, replacement, html_content)

        return html_content

    def generate_pdf_with_charts(self, output_path: str, chart_images: dict = None) -> str:
        """
        グラフ画像付きでPDFを生成

        Args:
            output_path: 出力ファイルパス
            chart_images: グラフ画像のパス辞書 {chart_id: image_path}

        Returns:
            出力ファイルパス

        Note:
            Chart.jsはJavaScript依存のため、PDFに直接レンダリングできません。
            事前にサーバーサイドでグラフ画像を生成するか、
            puppeteerなどのヘッドレスブラウザを使用する必要があります。
        """
        # chart_imagesがない場合は通常のPDF生成
        if not chart_images:
            return self.generate_pdf(output_path)

        # TODO: グラフ画像をHTMLに埋め込んでPDF生成
        # 現時点では通常のPDF生成
        return self.generate_pdf(output_path)
