<script lang="ts">
    import { onMount } from "svelte";
    import MediaItem from "$lib/MediaItem.svelte";
    import LogViewer from "$lib/LogViewer.svelte";
    import ImageCarousel from "$lib/ImageCarousel.svelte";
    import DualVideoViewer from "$lib/DualVideoViewer.svelte";
    import { formatDate } from "$lib/simulationState.svelte";

    let { data } = $props();
    let id = $derived(data.id);

    type SimulationDetails = {
        id: number;
        name: string;
        created_at: string;
        resources: string[];
        config: string | null;
        search_time: number | null;
        total_time: number | null;
        total_size_bytes: number;
    };

    let simulation = $state<SimulationDetails | null>(null);
    let error = $state("");

    function formatBytes(bytes: number) {
        if (bytes === 0) return "0 Bytes";
        const k = 1024;
        const sizes = ["Bytes", "KB", "MB", "GB"];
        const i = Math.floor(Math.log(bytes) / Math.log(k));
        return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + " " + sizes[i];
    }

    function flattenJSON(
        obj: any,
        prefix = "",
    ): { key: string; value: string }[] {
        let result: { key: string; value: string }[] = [];
        if (!obj) return result;
        for (let key in obj) {
            if (typeof obj[key] === "object" && obj[key] !== null) {
                if (Array.isArray(obj[key])) {
                    result.push({
                        key: prefix + key,
                        value: JSON.stringify(obj[key]),
                    });
                } else {
                    result = result.concat(
                        flattenJSON(obj[key], prefix + key + "."),
                    );
                }
            } else {
                result.push({ key: prefix + key, value: String(obj[key]) });
            }
        }
        return result;
    }

    let parsedConfig: { key: string; value: string }[] | null = $derived.by(
        () => {
            if (!simulation?.config) return null;
            try {
                let cleanedConfig = simulation.config.replace(
                    /"([^"]+)\.yaml"\s*:/g,
                    '"$1":',
                );
                return flattenJSON(JSON.parse(cleanedConfig));
            } catch {
                return null;
            }
        },
    );

    let searchConfig = $derived(
        parsedConfig?.filter((c) => c.key.startsWith("search.")),
    );
    let uavConfig = $derived(
        parsedConfig?.filter((c) => c.key.startsWith("uav.")),
    );
    let ugvConfig = $derived(
        parsedConfig?.filter((c) => c.key.startsWith("ugv.")),
    );
    let otherConfig = $derived(
        parsedConfig?.filter(
            (c) =>
                !c.key.startsWith("search.") &&
                !c.key.startsWith("uav.") &&
                !c.key.startsWith("ugv."),
        ),
    );

    function isImage(fname: string) {
        return (
            fname.toLowerCase().endsWith(".png") ||
            fname.toLowerCase().endsWith(".jpg") ||
            fname.toLowerCase().endsWith(".jpeg")
        );
    }

    function isVideo(fname: string) {
        return (
            fname.toLowerCase().endsWith(".mp4") ||
            fname.toLowerCase().endsWith(".avi") ||
            fname.toLowerCase().endsWith(".webm")
        );
    }

    let flightPathVideo: string | undefined = $derived(
        simulation && simulation.resources
            ? simulation.resources.find(
                  (res: string) => res.includes("flight_path") && isVideo(res),
              )
            : undefined,
    );

    let cameraVideo: string | undefined = $derived(
        simulation && simulation.resources
            ? simulation.resources.find(
                  (res: string) => res.includes("camera") && isVideo(res),
              )
            : undefined,
    );

    let imagesList = $derived<string[]>(
        simulation && simulation.resources
            ? simulation.resources.filter(isImage)
            : [],
    );
    let otherResourcesList = $derived<string[]>(
        simulation && simulation.resources
            ? simulation.resources.filter(
                  (res: string) =>
                      !isImage(res) &&
                      res !== "log.txt" &&
                      res !== flightPathVideo &&
                      res !== cameraVideo,
              )
            : [],
    );

    function getResourceUrl(simName: string, resourceName: string) {
        return `/results/${simName}/${resourceName}`;
    }

    onMount(async () => {
        try {
            const res = await fetch(`/api/simulations/${id}`);
            if (!res.ok) throw new Error("Failed to fetch simulation details");
            simulation = await res.json();
            newName = simulation!.name;
        } catch (e: any) {
            error = e.message;
        }
    });

    let isEditing = $state(false);
    let newName = $state("");
    let uploadFiles = $state<FileList | null>(null);
    let saveError = $state("");

    async function handleSave() {
        if (!simulation) return;
        saveError = "";

        // 1. Rename logic
        if (newName.trim() !== simulation.name) {
            const renameRes = await fetch(`/api/simulations/${id}/rename`, {
                method: "PUT",
                headers: { "Content-Type": "application/json" },
                body: JSON.stringify({ name: newName }),
            });

            if (!renameRes.ok) {
                const text = await renameRes.text();
                saveError = text || "Failed to rename simulation.";
                return;
            }

            const renameData = await renameRes.json();
            simulation.name = renameData.new_name;
        }

        // 2. Upload Logic
        if (uploadFiles && uploadFiles.length > 0) {
            for (let i = 0; i < uploadFiles.length; i++) {
                const formData = new FormData();
                formData.append("file", uploadFiles[i]);

                const uploadRes = await fetch(`/api/simulations/${id}/upload`, {
                    method: "POST",
                    body: formData,
                });

                if (!uploadRes.ok) {
                    saveError = `Failed to upload: ${uploadFiles[i].name}`;
                    return;
                }

                const upData = await uploadRes.json();
                if (!simulation.resources.includes(upData.filename)) {
                    simulation.resources = [
                        ...simulation.resources,
                        upData.filename,
                    ];
                }
            }
        }

        isEditing = false;
        uploadFiles = null;
    }

    function cancelEdit() {
        if (simulation) {
            newName = simulation.name;
        }
        isEditing = false;
        saveError = "";
        uploadFiles = null;
    }

    async function handleDelete() {
        if (
            !confirm(
                "Are you sure you want to permanently delete this simulation and all its associated media files?",
            )
        ) {
            return;
        }
        const res = await fetch(`/api/simulations/${id}`, {
            method: "DELETE",
        });

        if (res.ok) {
            // Force client-side redirect back to cleanly wiped root
            window.location.href = "/";
        } else {
            const text = await res.text();
            alert("Failed to delete the simulation: " + text);
        }
    }
</script>

<a href="/" class="back-link">&lt;&lt; Back to Index</a>

{#if error}
    <p class="error">Error: {error}</p>
{:else if !simulation}
    <p>Loading...</p>
{:else}
    <div class="header-container">
        {#if !isEditing}
            <h1>Simulation Detail: {simulation.name}</h1>
            <button class="edit-btn" onclick={() => (isEditing = true)}
                >Edit</button
            >
            <button class="delete-btn" onclick={handleDelete}>Delete</button>
        {:else}
            <div class="edit-form">
                <h2>Edit Simulation</h2>
                <div class="form-group">
                    <label for="sim-name">Name:</label>
                    <input id="sim-name" type="text" bind:value={newName} />
                </div>
                <div class="form-group">
                    <label for="sim-files">Upload Media:</label>
                    <input
                        id="sim-files"
                        type="file"
                        multiple
                        bind:files={uploadFiles}
                    />
                </div>
                {#if saveError}
                    <p class="error">{saveError}</p>
                {/if}
                <div class="form-actions">
                    <button class="save-btn" onclick={handleSave}>Save</button>
                    <button class="cancel-btn" onclick={cancelEdit}
                        >Cancel</button
                    >
                </div>
            </div>
        {/if}
    </div>

    <p>
        <strong>ID:</strong>
        {simulation.id}
    </p>
    <p>
        <strong>Search Pattern:</strong>
        <span style="text-transform: capitalize;"
            >{parsedConfig?.find((c) => c.key === "search.spiral.max_legs")
                ? "Spiral"
                : parsedConfig?.find((c) => c.key === "search.lawnmower.width")
                  ? "Lawnmower"
                  : parsedConfig?.find((c) => c.key === "search.levy.max_steps")
                    ? "Levy"
                    : "Unknown"}</span
        >
    </p>
    <p><strong>Date Code:</strong> {formatDate(simulation.created_at)}</p>

    {#if simulation.search_time !== null && simulation.total_time !== null}
        <p>
            <strong>Search Time:</strong>
            {simulation.search_time.toFixed(2)}s | <strong>Total Time:</strong>
            {simulation.total_time.toFixed(2)}s
        </p>
    {/if}
    <p>
        <strong>Total Media Size:</strong>
        {formatBytes(simulation.total_size_bytes || 0)}
    </p>

    {#if simulation.config}
        <div class="config-box">
            <strong>Configuration Options:</strong>
            {#if parsedConfig}
                {#snippet ConfigTable(
                    title: string,
                    data: { key: string; value: string }[] | undefined,
                )}
                    {#if data && data.length > 0}
                        <div class="table-wrapper">
                            <h3 class="table-label">{title}</h3>
                            <table class="config-table">
                                <thead>
                                    <tr>
                                        <th>Parameter</th>
                                        <th>Value</th>
                                    </tr>
                                </thead>
                                <tbody>
                                    {#each data as item}
                                        <tr>
                                            <td>{item.key}</td>
                                            <td>{item.value}</td>
                                        </tr>
                                    {/each}
                                </tbody>
                            </table>
                        </div>
                    {/if}
                {/snippet}

                <div class="tables-container">
                    {@render ConfigTable("Search", searchConfig)}
                    {@render ConfigTable("UGV", ugvConfig)}
                    {@render ConfigTable("UAV", uavConfig)}
                    {@render ConfigTable("Other", otherConfig)}
                </div>
            {:else}
                <pre>{simulation.config}</pre>
            {/if}
        </div>
    {/if}

    <hr />
    <h2>Simulation Logs</h2>
    {#if simulation.resources && simulation.resources.includes("log.txt")}
        <LogViewer simName={simulation.name} resourceName="log.txt" />
    {:else}
        <p>No log.txt file found for this simulation.</p>
    {/if}

    {#if flightPathVideo || cameraVideo}
        <hr />
        <h2>Flight Path & Camera</h2>
        <DualVideoViewer
            simName={simulation.name}
            video1={flightPathVideo}
            video2={cameraVideo}
            {getResourceUrl}
        />
    {/if}

    <hr />

    <h2>Media & Results</h2>
    {#if imagesList.length > 0}
        <ImageCarousel
            simName={simulation.name}
            images={imagesList}
            {getResourceUrl}
        />
    {/if}

    {#if otherResourcesList.length > 0}
        <div class="media-container">
            {#each otherResourcesList as res}
                <MediaItem simName={simulation.name} resourceName={res} />
            {/each}
        </div>
    {/if}

    {#if imagesList.length === 0 && otherResourcesList.length === 0}
        <p>No other media resources found for this simulation.</p>
    {/if}
{/if}

<style>
    :global(body) {
        font-family: "JetBrains Mono", Courier, monospace;
        background-color: #ffffff;
        color: #000000;
    }
    h1 {
        font-size: 24px;
    }
    h2 {
        font-size: 20px;
        margin-top: 30px;
        border-bottom: 1px solid #000;
    }
    a {
        color: #0000ff;
        text-decoration: underline;
    }
    a:visited {
        color: #800080;
    }
    .back-link {
        display: inline-block;
        margin-bottom: 20px;
    }
    .error {
        color: red;
        font-weight: bold;
    }
    hr {
        border: 0;
        border-top: 1px solid #000;
        margin: 20px 0;
    }
    .config-box {
        margin-top: 20px;
        border: 1px solid #000;
        padding: 10px;
        background-color: #f8f8f8;
        max-width: 100%;
        box-sizing: border-box;
        overflow-x: auto;
    }
    pre {
        margin: 10px 0 0 0;
        white-space: pre-wrap;
    }
    .table-label {
        margin: 0 0 5px 0;
        font-size: 16px;
        text-decoration: underline;
    }
    .tables-container {
        display: flex;
        flex-wrap: wrap;
        gap: 20px;
        align-items: flex-start;
        margin-top: 10px;
    }
    .table-wrapper {
        flex: 1 1 300px;
        max-width: 100%;
        overflow-x: auto;
    }
    .config-table {
        margin-top: 10px;
        width: 100%;
        border-collapse: collapse;
        background-color: #ffffff;
    }
    .config-table th,
    .config-table td {
        border: 1px solid #000;
        padding: 8px 10px;
        text-align: left;
        word-break: break-all;
    }
    .config-table th {
        background-color: #e0e0e0;
    }
    .header-container {
        display: flex;
        align-items: center;
        gap: 15px;
        margin-bottom: 20px;
    }
    .header-container h1 {
        margin: 0;
    }
    .edit-btn,
    .save-btn,
    .cancel-btn,
    .delete-btn {
        padding: 6px 15px;
        font-size: 14px;
        font-weight: bold;
        cursor: pointer;
        border: 1px solid #000;
        background-color: #e0e0e0;
        font-family: inherit;
    }
    .edit-btn:hover,
    .save-btn:hover,
    .cancel-btn:hover {
        background-color: #d0d0d0;
    }
    .delete-btn {
        background-color: #ffcccc;
        color: #990000;
        border-color: #990000;
        margin-left: auto;
    }
    .delete-btn:hover {
        background-color: #ff9999;
    }

    .edit-form {
        border: 1px dashed #000;
        padding: 15px;
        background-color: #f5f5f5;
        width: 100%;
    }
    .edit-form h2 {
        margin-top: 0;
        border-bottom: none;
    }
    .form-group {
        margin-bottom: 15px;
        display: flex;
        align-items: center;
        gap: 10px;
    }
    .form-group label {
        font-weight: bold;
        min-width: 120px;
    }
    .form-group input[type="text"] {
        flex: 1;
        max-width: 400px;
        padding: 5px;
        font-family: inherit;
        border: 1px solid #000;
    }
    .form-group input[type="file"] {
        font-family: inherit;
        font-size: 14px;
        cursor: pointer;
    }
    .form-group input[type="file"]::file-selector-button {
        padding: 6px 15px;
        font-size: 14px;
        font-weight: bold;
        cursor: pointer;
        border: 1px solid #000;
        background-color: #e0e0e0;
        font-family: inherit;
        margin-right: 10px;
    }
    .form-group input[type="file"]::file-selector-button:hover {
        background-color: #d0d0d0;
    }
    .form-actions {
        display: flex;
        gap: 10px;
        margin-top: 10px;
    }
</style>
