#!/usr/bin/env xonsh
"""script for compiling elm source and dumping it to the js folder."""
import os
import io
import tempfile
from pprint import pprint

import pygments
from pygments.lexers import Python3Lexer
from pygments.formatters.html import HtmlFormatter

from xonsh.tools import print_color, format_color
from xonsh.style_tools import partial_color_tokenize
from xonsh.color_tools import rgb_to_ints
from xonsh.pygments_cache import get_all_styles
from xonsh.pyghooks import XonshStyle, xonsh_style_proxy, XonshHtmlFormatter, Token, XonshLexer
from xonsh.prompt.base import PromptFormatter
from xonsh.xontribs_meta import get_xontribs, Xontrib


$RAISE_SUBPROC_ERROR = True
$XONSH_SHOW_TRACEBACK = False

#
# helper funcs
#

def escape(s):
    return s.replace("\n", "").replace('"', '\\"')


def invert_color(orig):
    r, g, b = rgb_to_ints(orig)
    inverted = [255 - r, 255 - g, 255 - b]
    new = [hex(n)[2:] for n in inverted]
    new = [n if len(n) == 2 else '0' + n for n in new]
    return ''.join(new)


def html_format(s, style="default"):
    buf = io.StringIO()
    proxy_style = xonsh_style_proxy(XonshStyle(style))
    # make sure we have a foreground color
    fgcolor = proxy_style._styles[Token.Text][0]
    if not fgcolor:
        fgcolor = invert_color(proxy_style.background_color[1:].strip('#'))
    # need to generate stream before creating formatter so that all tokens actually exist
    if isinstance(s, str):
        token_stream = partial_color_tokenize(s)
    else:
        token_stream = s
    formatter = XonshHtmlFormatter(
        wrapcode=True,
        noclasses=True,
        style=proxy_style,
        prestyles="margin: 0em; padding: 0.5em 0.1em; color: #" + fgcolor,
        cssstyles="border-style: solid; border-radius: 5px",
    )
    formatter.format(token_stream, buf)
    return buf.getvalue()


def rst_to_html(s):
    template = "%(body)s"
    with tempfile.NamedTemporaryFile('w+') as t, tempfile.NamedTemporaryFile('w+') as f:
        t.write(template)
        t.flush()
        f.write(s)
        f.flush()
        html = $(rst2html5.py --template @(t.name) @(f.name))
    return html


#
# first, write out elm-src/XonshData.elm
#
XONSH_DATA_HEADER = """-- A collection of xonsh values for the web-ui
-- This file has been auto-generated by elm-compile.xsh
module XonshData exposing (..)

import List
import String

"""

# render prompts
PROMPTS = [
    ("default", '{env_name}{BOLD_GREEN}{user}@{hostname}{BOLD_BLUE} {cwd}'
                '{branch_color}{curr_branch: {}}{RESET} {BOLD_BLUE}'
                '{prompt_end}{RESET} '),
    ("debian chroot", '{BOLD_GREEN}{user}@{hostname}{BOLD_BLUE} {cwd}{RESET}> '),
    ("minimalist", '{BOLD_GREEN}{cwd_base}{RESET} ) '),
    ("terlar", '{env_name}{BOLD_GREEN}{user}{RESET}@{hostname}:'
               '{BOLD_GREEN}{cwd}{RESET}|{gitstatus}\\n{BOLD_INTENSE_RED}➤{RESET} '),
    ("default with git status", '{env_name}{BOLD_GREEN}{user}@{hostname}{BOLD_BLUE} {cwd}'
                '{branch_color}{gitstatus: {}}{RESET} {BOLD_BLUE}'
                '{prompt_end}{RESET} '),
    ("robbyrussell", '{BOLD_INTENSE_RED}➜ {CYAN}{cwd_base} {gitstatus}{RESET} '),
    ("just a dollar", "$ "),
    ("simple pythonista", "{INTENSE_RED}{user}{RESET} at {INTENSE_PURPLE}{hostname}{RESET} "
                          "in {BOLD_GREEN}{cwd}{RESET}\\n↪ "),
    ("informative", "[{localtime}] {YELLOW}{env_name} {BOLD_BLUE}{user}@{hostname} "
                    "{BOLD_GREEN}{cwd} {gitstatus}{RESET}\\n> "),
    ("informative Version Control", "{YELLOW}{env_name} "
                    "{BOLD_GREEN}{cwd} {gitstatus}{RESET} {prompt_end} "),
    ("classic", "{user}@{hostname} {BOLD_GREEN}{cwd}{RESET}> "),
    ("classic with git status", "{gitstatus} {RESET}{user}@{hostname} {BOLD_GREEN}{cwd}{RESET}> "),
    ("screen savvy", "{YELLOW}{user}@{PURPLE}{hostname}{BOLD_GREEN}{cwd}{RESET}> "),
    ("sorin", "{CYAN}{cwd} {INTENSE_RED}❯{INTENSE_YELLOW}❯{INTENSE_GREEN}❯{RESET} "),
    ("acidhub", "❰{INTENSE_GREEN}{user}{RESET}❙{YELLOW}{cwd}{RESET}{env_name}❱{gitstatus}≻ "),
    ("nim", "{INTENSE_GREEN}┬─[{YELLOW}{user}{RESET}@{BLUE}{hostname}{RESET}:{cwd}"
            "{INTENSE_GREEN}]─[{localtime}]─[{RESET}G:{INTENSE_GREEN}{curr_branch}=]"
            "\\n{INTENSE_GREEN}╰─>{INTENSE_RED}{prompt_end}{RESET} "),
]

prompt_header = """type alias PromptData =
    { name : String
    , value : String
    , display : String
    }

prompts : List PromptData
prompts ="""

def render_prompts(lines):
    print_color("Rendering {GREEN}prompts{RESET}")
    prompt_format = PromptFormatter()
    fields = dict($PROMPT_FIELDS)
    fields.update(
        cwd="~/snail/stuff",
        cwd_base="stuff",
        user="lou",
        hostname="carcolh",
        env_name=fields['env_prefix'] + "env" + fields["env_postfix"],
        curr_branch="branch",
        gitstatus="{CYAN}branch|{BOLD_BLUE}+2{RESET}⚑7",
        branch_color="{BOLD_INTENSE_RED}",
        localtime="15:56:07",
    )
    lines.append(prompt_header)
    for i, (name, template) in enumerate(PROMPTS):
        display = html_format(prompt_format(template, fields=fields))
        item = 'name = "' + name + '", '
        item += 'value = "' + escape(template) + '", '
        item += 'display = "' + escape(display) + '"'
        pre = "    [ " if i == 0 else "    , "
        lines.append(pre + "{ " + item + " }")
    lines.append("    ]")


# render color data

color_header = """
type alias ColorData =
    { name : String
    , display : String
    }

colors : List ColorData
colors ="""

def render_colors(lines):
    print_color("Rendering {GREEN}color styles{RESET}")
    source = (
        'import sys\n'
        'echo "Welcome $USER on" @(sys.platform)\n\n'
        'def func(x=42):\n'
        '    d = {"xonsh": True}\n'
        '    return d.get("xonsh") and you\n\n'
        '# This is a comment\n'
        '![env | uniq | sort | grep PATH]\n'
    )
    lexer = XonshLexer()
    lexer.add_filter('tokenmerge')
    token_stream = list(pygments.lex(source, lexer=lexer))
    token_stream = [(t, s.replace("\n", "\\n")) for t, s in token_stream]
    lines.append(color_header)
    styles = sorted(get_all_styles())
    styles.insert(0, styles.pop(styles.index("default")))
    for i, style in enumerate(styles):
        display = html_format(token_stream, style=style)
        item = 'name = "' + style + '", '
        item += 'display = "' + escape(display) + '"'
        pre = "    [ " if i == 0 else "    , "
        lines.append(pre + "{ " + item + " }")
    lines.append("    ]")


# render xontrib data

xontrib_header = """
type alias XontribData =
    { name : String
    , url : String
    , license : String
    , description : String
    }

xontribs : List XontribData
xontribs ="""


def get_xontrib_item(xontrib_name: str, xontrib: Xontrib):
    item = 'name = "' + xontrib_name + '", '
    item += 'url = "' + xontrib.url + '", '
    item += 'license = "' + (xontrib.package.license if xontrib.package else "") + '", '
    d = rst_to_html("".join(xontrib.description)).replace("\n", "\\n")
    item += 'description = "' + escape(d) + '"'
    return item


def render_xontribs(lines):
    print_color("Rendering {GREEN}xontribs{RESET}")
    lines.append(xontrib_header)
    md = get_xontribs()
    for i, xontrib_name in enumerate(md):
        xontrib = md[xontrib_name]
        item = get_xontrib_item(xontrib_name, xontrib)
        pre = "    [ " if i == 0 else "    , "
        lines.append(pre + "{ " + item + " }")
    lines.append("    ]")


def write_xonsh_data():
    # write XonshData.elm
    lines = [XONSH_DATA_HEADER]
    render_prompts(lines)
    render_colors(lines)
    render_xontribs(lines)
    src = "\n".join(lines) + "\n"
    xdelm = os.path.join('elm-src', 'XonshData.elm')
    with open(xdelm, 'w') as f:
        f.write(src)


#
# now compile the sources
#
SOURCES = [
    'App.elm',
]
with ${...}.swap(RAISE_SUBPROC_ERROR=False):
    HAVE_UGLIFY = bool(!(which uglifyjs e>o))

UGLIFY_FLAGS = ('pure_funcs="F2,F3,F4,F5,F6,F7,F8,F9,A2,A3,A4,A5,A6,A7,A8,A9",'
                'pure_getters,keep_fargs=false,unsafe_comps,unsafe')


def compile():
    for source in SOURCES:
        base = os.path.splitext(source.lower())[0]
        src = os.path.join('elm-src', source)
        js_target = os.path.join('js', base + '.js')
        print_color('Compiling {YELLOW}' + src + '{RESET} -> {GREEN}' +
                    js_target + '{RESET}')
        $XONSH_SHOW_TRACEBACK = False
        try:
            ![elm make --optimize --output @(js_target) @(src)]
        except Exception:
            import sys
            sys.exit(1)
        new_files = [js_target]
        min_target = os.path.join('js', base + '.min.js')
        if os.path.exists(min_target):
            ![rm -v @(min_target)]
        if HAVE_UGLIFY:
            print_color('Minifying {YELLOW}' + js_target + '{RESET} -> {GREEN}' +
                        min_target + '{RESET}')
            ![uglifyjs @(js_target) --compress @(UGLIFY_FLAGS) |
              uglifyjs --mangle --output @(min_target)]
            new_files.append(min_target)
        ![ls -l @(new_files)]


def main():
    write_xonsh_data()
    compile()


if __name__ == "__main__":
    main()
