#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
@Time    : 2023/9/4 16:12
@Author  : Steven Lee
@File    : mmdc_playwright.py
"""

import os
from urllib.parse import urljoin
from playwright.async_api import async_playwright
from metagpt.logs import logger

async def mermaid_to_file(mermaid_code, output_file_without_suffix, width=2048, height=2048)-> int:
    """
    Converts the given Mermaid code to various output formats and saves them to files.

    Args:
        mermaid_code (str): The Mermaid code to convert.
        output_file_without_suffix (str): The output file name without the file extension.
        width (int, optional): The width of the output image in pixels. Defaults to 2048.
        height (int, optional): The height of the output image in pixels. Defaults to 2048.

    Returns:
        int: Returns 1 if the conversion and saving were successful, -1 otherwise.
    """
    suffixes=['png', 'svg', 'pdf']
    __dirname = os.path.dirname(os.path.abspath(__file__))

    async with async_playwright() as p:
        browser = await p.chromium.launch()
        device_scale_factor = 1.0
        context = await browser.new_context(
                viewport={'width': width, 'height': height},
                device_scale_factor=device_scale_factor,
            )
        page = await context.new_page()

        async def console_message(msg):
            logger.info(msg.text)
        page.on('console', console_message)

        try:
            await page.set_viewport_size({'width': width, 'height': height})

            mermaid_html_path = os.path.abspath(
                os.path.join(__dirname, 'index.html'))
            mermaid_html_url = urljoin('file:', mermaid_html_path)
            await page.goto(mermaid_html_url)
            await page.wait_for_load_state("networkidle")

            await page.wait_for_selector("div#container", state="attached")
            mermaid_config = {}
            background_color = "#ffffff"
            my_css = ""
            await page.evaluate(f'document.body.style.background = "{background_color}";')

            metadata = await page.evaluate('''async ([definition, mermaidConfig, myCSS, backgroundColor]) => {
                const { mermaid, zenuml } = globalThis;
                await mermaid.registerExternalDiagrams([zenuml]);
                mermaid.initialize({ startOnLoad: false, ...mermaidConfig });
                const { svg } = await mermaid.render('my-svg', definition, document.getElementById('container'));
                document.getElementById('container').innerHTML = svg;
                const svgElement = document.querySelector('svg');
                svgElement.style.backgroundColor = backgroundColor;

                if (myCSS) {
                    const style = document.createElementNS('http://www.w3.org/2000/svg', 'style');
                    style.appendChild(document.createTextNode(myCSS));
                    svgElement.appendChild(style);
                }

            }''', [mermaid_code, mermaid_config, my_css, background_color])

            if 'svg' in suffixes :
                svg_xml = await page.evaluate('''() => {
                    const svg = document.querySelector('svg');
                    const xmlSerializer = new XMLSerializer();
                    return xmlSerializer.serializeToString(svg);
                }''')
                logger.info(f"Generating {output_file_without_suffix}.svg..")
                with open(f'{output_file_without_suffix}.svg', 'wb') as f:
                    f.write(svg_xml.encode('utf-8'))

            if  'png' in suffixes:
                clip = await page.evaluate('''() => {
                    const svg = document.querySelector('svg');
                    const rect = svg.getBoundingClientRect();
                    return {
                        x: Math.floor(rect.left),
                        y: Math.floor(rect.top),
                        width: Math.ceil(rect.width),
                        height: Math.ceil(rect.height)
                    };
                }''')
                await page.set_viewport_size({'width': clip['x'] + clip['width'], 'height': clip['y'] + clip['height']})
                screenshot = await page.screenshot(clip=clip, omit_background=True, scale='device')
                logger.info(f"Generating {output_file_without_suffix}.png..")
                with open(f'{output_file_without_suffix}.png', 'wb') as f:
                    f.write(screenshot)
            if 'pdf' in suffixes:
                pdf_data = await page.pdf(scale=device_scale_factor)
                logger.info(f"Generating {output_file_without_suffix}.pdf..")
                with open(f'{output_file_without_suffix}.pdf', 'wb') as f:
                    f.write(pdf_data)
            return 0
        except Exception as e:
            logger.error(e)
            return -1
        finally:
            await browser.close()
