import http.server
import socketserver
import json
import os
import subprocess
from urllib.parse import parse_qs, urlparse
import mimetypes
import html

# --- Theme selection (choose one: "light1", "light2", "dark1", "dark2") ---
THEME = "light1"  # Change this to "light2", "dark1", or "dark2" as desired

THEMES = {
    "light1": """
        body { font-family: Arial, sans-serif; background: #f6f8fa; margin: 0; padding: 0; color: #222; }
        .container { max-width: 960px; margin: auto; padding: 2em; }
        .date-header { font-size: 1.2em; margin-top: 2em; border-bottom: 1px solid #ccc; }
        .commit { margin: 1em 0; padding: 1em; background: #fff; border-radius: 6px; box-shadow: 0 1px 3px rgba(0,0,0,0.07); }
        .hash { color: #555; font-family: monospace; }
        .diff { white-space: pre-wrap; background: #f1f1f1; padding: 1em; border-radius: 4px; overflow-x: auto; }
        ul { list-style: none; padding-left: 0; }
        li { margin: 0.3em 0; }
        a { text-decoration: none; color: #0366d6; }
        a:hover { text-decoration: underline; }
    """,
    "light2": """
        body { font-family: 'Segoe UI', sans-serif; background: #fdf6e3; margin: 0; padding: 0; color: #333; }
        .container { max-width: 900px; margin: auto; padding: 2em; }
        .date-header { font-size: 1.2em; margin-top: 2em; border-bottom: 2px solid #e1c699; color: #b58900; }
        .commit { margin: 1em 0; padding: 1em; background: #fffbe6; border-radius: 6px; box-shadow: 0 1px 3px rgba(200,180,100,0.08); }
        .hash { color: #b58900; font-family: monospace; }
        .diff { white-space: pre-wrap; background: #f5e9c9; padding: 1em; border-radius: 4px; overflow-x: auto; }
        ul { list-style: none; padding-left: 0; }
        li { margin: 0.3em 0; }
        a { text-decoration: none; color: #b58900; }
        a:hover { text-decoration: underline; color: #cb4b16; }
    """,
    "dark1": """
        body { font-family: Arial, sans-serif; background: #181a1b; margin: 0; padding: 0; color: #eaeaea; }
        .container { max-width: 960px; margin: auto; padding: 2em; }
        .date-header { font-size: 1.2em; margin-top: 2em; border-bottom: 1px solid #333; color: #8ab4f8; }
        .commit { margin: 1em 0; padding: 1em; background: #23272b; border-radius: 6px; box-shadow: 0 1px 3px rgba(0,0,0,0.18); }
        .hash { color: #8ab4f8; font-family: monospace; }
        .diff { white-space: pre-wrap; background: #23272b; padding: 1em; border-radius: 4px; overflow-x: auto; }
        ul { list-style: none; padding-left: 0; }
        li { margin: 0.3em 0; }
        a { text-decoration: none; color: #8ab4f8; }
        a:hover { text-decoration: underline; color: #bb86fc; }
    """,
    "dark2": """
        body { font-family: 'Fira Sans', sans-serif; background: #121212; margin: 0; padding: 0; color: #d0d0d0; }
        .container { max-width: 900px; margin: auto; padding: 2em; }
        .date-header { font-size: 1.2em; margin-top: 2em; border-bottom: 2px solid #444; color: #ffb86c; }
        .commit { margin: 1em 0; padding: 1em; background: #22223b; border-radius: 6px; box-shadow: 0 1px 3px rgba(0,0,0,0.22); }
        .hash { color: #ffb86c; font-family: monospace; }
        .diff { white-space: pre-wrap; background: #282a36; padding: 1em; border-radius: 4px; overflow-x: auto; }
        ul { list-style: none; padding-left: 0; }
        li { margin: 0.3em 0; }
        a { text-decoration: none; color: #ffb86c; }
        a:hover { text-decoration: underline; color: #8be9fd; }
    """,
}

def HTML_TEMPLATE(content, theme=THEME):
    return f"""
<!DOCTYPE html>
<html lang=\"en\">
<head>
    <meta charset=\"UTF-8\">
    <title>Git Log Viewer</title>
    <link rel=\"stylesheet\" href=\"https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/github.min.css\">
    <style>
        {THEMES[theme]}
    </style>
    <script src=\"https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js\"></script>
    <script>hljs.highlightAll();</script>
</head>
<body>
    <div class=\"container\">
        {content}
    </div>
</body>
</html>
"""

REPO_ROOT = os.path.abspath(".")
LOG_FILE = os.path.join(REPO_ROOT, "gitlog.jsonl")

PORT = 8481

def format_diff_to_html(diff_text: str) -> str:
    lines = diff_text.strip().splitlines()
    html_lines = ['<div style="font-family: monospace; white-space: pre;">']
    while not lines[3].startswith('diff'):
        lines.pop(3)
    lines.insert(3, "")
    for line in lines:
        escaped = html.escape(line)
        if "//" in line:
            continue 
        if "#" in line:
            continue
        if "/*" in line:
            continue
        if "*/" in line:
            continue
        if line.startswith('+++') or line.startswith('---'):
            html_lines.append(f'<div style="color: #0000aa;">{escaped}</div>')
        elif line.startswith('@@'):
            html_lines.append(f'<div style="color: #005cc5;">{escaped}</div>')
        elif line.startswith('+'):
            html_lines.append(f'<div style="color: #22863a;">{escaped}</div>')
        elif line.startswith('-'):
            html_lines.append(f'<div style="color: #b31d28;">{escaped}</div>')
        elif line.startswith('\\'):
            html_lines.append(f'<div style="color: #6a737d;">{escaped}</div>')
        else:
            html_lines.append(f'<div>{escaped}</div>')
    html_lines.append('</div>')
    return '\n'.join(html_lines)

def parse_logs():
    logs = []
    if not os.path.exists(LOG_FILE):
        return []
    lines = []
    with open(LOG_FILE, "r", encoding="utf-8") as f:
        for line in f:
            if line.strip():
                if line.strip() not in lines:
                    lines.append(line.strip())
                    logs.append(json.loads(line.strip()))
    return logs

def group_by_date(logs):
    grouped = {}
    for entry in logs:
        date = entry["date"]
        grouped.setdefault(date, []).append(entry)
    return dict(sorted(grouped.items(), reverse=True))

def get_git_diff(commit_hash):
    try:
        result = subprocess.run(
            ["git", "-C", REPO_ROOT, "show", commit_hash, "--no-color"],
            stdout=subprocess.PIPE,
            stderr=subprocess.PIPE,
            text=True,
            check=True,
        )
        return result.stdout
    except subprocess.CalledProcessError as e:
        return f"Error retrieving diff: {e.stderr}"

def list_directory(path, base_url="/browse?path="):
    try:
        entries = os.listdir(path)
    except OSError:
        return "<div>Cannot access directory.</div>"

    entries.sort()
    content = "<ul>"
    # Parent directory link
    parent = os.path.dirname(path)
    if os.path.abspath(path) != REPO_ROOT:
        parent_rel = os.path.relpath(parent, REPO_ROOT)
        content += f"<li><a href='{base_url}{html.escape(parent_rel)}'>.. (parent directory)</a></li>"

    for entry in entries:
        full_path = os.path.join(path, entry)
        rel_path = os.path.relpath(full_path, REPO_ROOT)
        if os.path.isdir(full_path):
            content += f"<li>📁 <a href='{base_url}{html.escape(rel_path)}'>{html.escape(entry)}/</a></li>"
        else:
            content += f"<li>📄 <a href='{base_url}{html.escape(rel_path)}'>{html.escape(entry)}</a></li>"
    content += "</ul>"
    return content

def read_file_content(path):
    try:
        with open(path, "r", encoding="utf-8") as f:
            return f.read()
    except Exception as e:
        return f"Error reading file: {e}"

def get_language_class(filename):
    ext = os.path.splitext(filename)[1].lower()
    return {
        '.py': 'python',
        '.js': 'javascript',
        '.html': 'html',
        '.css': 'css',
        '.json': 'json',
        '.sh': 'bash',
        '.md': 'markdown',
        '.c': 'c',
        '.cpp': 'cpp',
        '.h': 'cpp',
        '.java': 'java',
        '.rb': 'ruby',
        '.go': 'go',
        '.php': 'php',
        '.rs': 'rust',
        '.ts': 'typescript',
        '.xml': 'xml',
        '.yml': 'yaml',
        '.yaml': 'yaml',
    }.get(ext, '')

class GitLogHandler(http.server.SimpleHTTPRequestHandler):
    def do_GET(self):
        parsed = urlparse(self.path)
        if parsed.path == "/":
            self.send_response(200)
            self.send_header("Content-type", "text/html")
            self.end_headers()
            logs = parse_logs()
            grouped = group_by_date(logs)
            content = "<p><a href='/browse'>Browse Files</a></p>"
            for date, commits in grouped.items():
                content += f"<div class='date-header'>{date}</div>"
                for c in commits:
                    commit_link = f"/diff?hash={c['commit']}"
                    content += f"""
                    <div class='commit'>
                        <div><strong>{c['line'].splitlines()[0]}</strong></div>
                        <div class='hash'><a href='{commit_link}'>{c['commit']}</a></div>
                    </div>
                    """
            self.wfile.write(HTML_TEMPLATE(content).encode("utf-8"))
        elif parsed.path == "/diff":
            qs = parse_qs(parsed.query)
            commit = qs.get("hash", [""])[0]
            diff = format_diff_to_html(get_git_diff(html.escape(commit)))
            diff_html = f"<h2>Commit: {commit}</h2><div class='diff'>{diff}</div><p><a href='/'>← Back to commits</a></p>"
            self.send_response(200)
            self.send_header("Content-type", "text/html")
            self.end_headers()
            self.wfile.write(HTML_TEMPLATE(diff_html).encode("utf-8"))
        elif parsed.path == "/browse":
            qs = parse_qs(parsed.query)
            rel_path = qs.get("path", [""])[0]
            abs_path = os.path.abspath(os.path.join(REPO_ROOT, rel_path))
            # Security: prevent escaping the repo root
            if not abs_path.startswith(REPO_ROOT):
                self.send_error(403, "Forbidden")
                return

            if os.path.isdir(abs_path):
                content = f"<h2>Browsing: /{html.escape(rel_path)}</h2>"
                content += list_directory(abs_path)
                content += "<p><a href='/'>← Back to commits</a></p>"
                self.send_response(200)
                self.send_header("Content-type", "text/html")
                self.end_headers()
                self.wfile.write(HTML_TEMPLATE(content).encode("utf-8"))
            elif os.path.isfile(abs_path):
                file_content = read_file_content(abs_path)
                lang_class = get_language_class(abs_path)
                content = f"<h2>File: /{html.escape(rel_path)}</h2>"
                content += (
                    f"<pre style='background:#f1f1f1; padding:1em; border-radius:4px; overflow-x:auto;'>"
                    f"<code class='{lang_class}'>{html.escape(file_content)}</code></pre>"
                )
                content += "<p><a href='{}'>← Back to directory</a></p>".format(
                    f"/browse?path={html.escape(os.path.dirname(rel_path))}"
                )
                self.send_response(200)
                self.send_header("Content-type", "text/html")
                self.end_headers()
                self.wfile.write(HTML_TEMPLATE(content).encode("utf-8"))
            else:
                self.send_error(404, "Not found")
        else:
            self.send_error(404)

if __name__ == "__main__":
    
    while True:
        try:
            with socketserver.TCPServer(("", PORT), GitLogHandler) as httpd:
                print(f"Serving at http://localhost:{PORT}")
                httpd.serve_forever()
                break
        except Exception as ex:
            print(ex)
            PORT += 1


