#!/usr/bin/env python3

from http.server import ThreadingHTTPServer, SimpleHTTPRequestHandler
from pathlib import Path
import html
import json
import os
import xml.etree.ElementTree as ET

PORT = 8000
BASE_DIR = Path(__file__).resolve().parent


def get_school_name(xml_file):
    try:
        root = ET.parse(xml_file).getroot()

        candidates = [
            ".//{*}OrganizationDisplayName",
            ".//{*}OrganizationName",
            ".//{*}DisplayName",
            ".//{*}ServiceName",
        ]

        for xpath in candidates:
            element = root.find(xpath)

            if element is not None and element.text and element.text.strip():
                return element.text.strip()

        entity_id = root.attrib.get("entityID")
        if entity_id:
            return entity_id

    except Exception:
        pass

    return (
        xml_file.stem
        .replace("_", " ")
        .replace("-", " ")
        .title()
    )


class MetadataHandler(SimpleHTTPRequestHandler):

    def do_GET(self):
        request_path = self.path.split("?", 1)[0]

        if request_path in ("/", "/index.html"):
            self.show_index()
            return

        super().do_GET()

    def show_index(self):
        files = sorted(
            BASE_DIR.glob("*.xml"),
            key=lambda p: get_school_name(p).lower()
        )

        rows = []

        for xml_file in files:
            filename = xml_file.name
            school_name = get_school_name(xml_file)

            safe_name = html.escape(school_name)
            safe_filename = html.escape(filename)
            search_text = html.escape(
                (school_name + " " + filename).lower()
            )

            filename_js = json.dumps(filename)

            row = """
            <div class="school-row" data-search="__SEARCH__">

                <div class="school-info">
                    <div class="school-name">__SCHOOL_NAME__</div>
                    <div class="filename">__FILENAME__</div>
                </div>

                <div class="actions">
                    <button
                        class="copy-btn"
                        onclick='copyXML(__FILENAME_JS__)'>
                        Copy XML
                    </button>

                    <a
                        class="view-btn"
                        href="__FILENAME_URL__"
                        target="_blank">
                        View XML
                    </a>
                </div>

            </div>
            """

            row = row.replace("__SEARCH__", search_text)
            row = row.replace("__SCHOOL_NAME__", safe_name)
            row = row.replace("__FILENAME__", safe_filename)
            row = row.replace("__FILENAME_JS__", filename_js)
            row = row.replace("__FILENAME_URL__", safe_filename)

            rows.append(row)

        page = """<!DOCTYPE html>
<html lang="en">

<head>

<meta charset="UTF-8">

<meta
    name="viewport"
    content="width=device-width, initial-scale=1">

<title>RIF School Metadata</title>

<style>

* {
    box-sizing: border-box;
}

body {
    margin: 0;
    font-family: Arial, Helvetica, sans-serif;
    background: #f4f6f8;
    color: #222;
}

header {
    background: #163d67;
    color: white;
    padding: 28px 20px;
}

.header-inner {
    max-width: 1100px;
    margin: 0 auto;
}

header h1 {
    margin: 0 0 6px 0;
    font-size: 28px;
}

header p {
    margin: 0;
    opacity: 0.9;
}

.container {
    max-width: 1100px;
    margin: 25px auto;
    padding: 0 15px 40px 15px;
}

.toolbar {
    margin-bottom: 18px;
}

#search {
    width: 100%;
    padding: 14px 16px;
    font-size: 16px;
    border: 1px solid #c7cdd3;
    border-radius: 8px;
    outline: none;
    background: white;
}

#search:focus {
    border-color: #163d67;
}

.result-count {
    margin-top: 10px;
    color: #666;
    font-size: 14px;
}

.school-row {
    background: white;
    border-radius: 8px;
    padding: 16px 18px;
    margin-bottom: 10px;

    display: flex;
    justify-content: space-between;
    align-items: center;

    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.12);
}

.school-info {
    min-width: 0;
}

.school-name {
    font-size: 17px;
    font-weight: bold;
    word-break: break-word;
}

.filename {
    color: #777;
    font-size: 13px;
    margin-top: 5px;
    word-break: break-all;
}

.actions {
    display: flex;
    gap: 8px;
    margin-left: 20px;
    flex-shrink: 0;
}

button,
.view-btn {
    border: none;
    padding: 10px 15px;
    border-radius: 5px;
    cursor: pointer;
    text-decoration: none;
    font-size: 14px;
    white-space: nowrap;
}

.copy-btn {
    background: #087f5b;
    color: white;
}

.copy-btn:hover {
    background: #06684a;
}

.view-btn {
    background: #e9ecef;
    color: #333;
}

.view-btn:hover {
    background: #dce1e5;
}

#toast {
    position: fixed;
    right: 20px;
    bottom: 20px;

    background: #222;
    color: white;

    padding: 13px 20px;
    border-radius: 6px;

    display: none;

    box-shadow: 0 3px 10px rgba(0, 0, 0, 0.25);

    z-index: 1000;
}

.no-results {
    background: white;
    padding: 25px;
    text-align: center;
    color: #777;
    border-radius: 8px;
    display: none;
}

@media (max-width: 650px) {

    .school-row {
        align-items: flex-start;
        flex-direction: column;
    }

    .actions {
        margin-left: 0;
        margin-top: 12px;
        width: 100%;
    }

    .actions button,
    .actions a {
        flex: 1;
        text-align: center;
    }
}

</style>

</head>

<body>

<header>
    <div class="header-inner">
        <h1>RIF School Metadata</h1>
        <p>__FILE_COUNT__ metadata files available</p>
    </div>
</header>

<div class="container">

    <div class="toolbar">

        <input
            type="text"
            id="search"
            placeholder="Search school or metadata file..."
            autocomplete="off"
            oninput="filterSchools()">

        <div
            class="result-count"
            id="result-count">
            Showing __FILE_COUNT__ schools
        </div>

    </div>

    <div id="schools">
        __ROWS__
    </div>

    <div
        id="no-results"
        class="no-results">
        No matching school found.
    </div>

</div>

<div id="toast">
    XML copied to clipboard
</div>

<script>

async function copyXML(filename) {

    try {

        const response = await fetch(
            encodeURIComponent(filename),
            {
                cache: "no-store"
            }
        );

        if (!response.ok) {
            throw new Error(
                "HTTP " + response.status
            );
        }

        let xml = await response.text();

        /*
         * Remove XML declaration from the beginning.
         *
         * Removes lines like:
         * <?xml version='1.0' encoding='utf-8'?>
         */

        xml = xml.replace(
            /^\uFEFF?\s*<\?xml[^?]*\?>\s*/,
            ""
        );

        try {

            await navigator.clipboard.writeText(xml);

        } catch (clipboardError) {

            const textarea =
                document.createElement("textarea");

            textarea.value = xml;
            textarea.style.position = "fixed";
            textarea.style.left = "-9999px";
            textarea.style.top = "0";

            document.body.appendChild(textarea);

            textarea.focus();
            textarea.select();

            const copied =
                document.execCommand("copy");

            document.body.removeChild(textarea);

            if (!copied) {
                throw clipboardError;
            }
        }

        showToast(
            "Copied " + filename
        );

    } catch (error) {

        console.error(error);

        alert(
            "Unable to copy XML: " +
            error.message
        );
    }
}


function showToast(message) {

    const toast =
        document.getElementById("toast");

    toast.innerText = message;
    toast.style.display = "block";

    clearTimeout(window.toastTimer);

    window.toastTimer =
        setTimeout(() => {
            toast.style.display = "none";
        }, 2000);
}


function filterSchools() {

    const search =
        document
            .getElementById("search")
            .value
            .trim()
            .toLowerCase();

    const rows =
        document.querySelectorAll(
            ".school-row"
        );

    let visible = 0;

    rows.forEach(row => {

        const searchable =
            row.dataset.search;

        const match =
            searchable.includes(search);

        row.style.display =
            match ? "flex" : "none";

        if (match) {
            visible++;
        }
    });

    document
        .getElementById("result-count")
        .innerText =
        "Showing " +
        visible +
        " school" +
        (visible === 1 ? "" : "s");

    document
        .getElementById("no-results")
        .style.display =
        visible === 0
            ? "block"
            : "none";
}

</script>

</body>

</html>
"""

        page = page.replace(
            "__FILE_COUNT__",
            str(len(files))
        )

        page = page.replace(
            "__ROWS__",
            "".join(rows)
        )

        encoded = page.encode("utf-8")

        self.send_response(200)

        self.send_header(
            "Content-Type",
            "text/html; charset=utf-8"
        )

        self.send_header(
            "Content-Length",
            str(len(encoded))
        )

        self.send_header(
            "Cache-Control",
            "no-store"
        )

        self.end_headers()

        self.wfile.write(encoded)


if __name__ == "__main__":

    os.chdir(BASE_DIR)

    server = ThreadingHTTPServer(
        ("0.0.0.0", PORT),
        MetadataHandler
    )

    print(f"Serving metadata from: {BASE_DIR}")
    print(f"Listening on: http://0.0.0.0:{PORT}/")
    print(f"Metadata files found: {len(list(BASE_DIR.glob('*.xml')))}")

    try:
        server.serve_forever()

    except KeyboardInterrupt:
        print("\nStopping server...")
        server.server_close()
