<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>EdgeAI Digit Reader</title>
    
    <!-- External Libraries -->
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
    <link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css" rel="stylesheet">
    <link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/npm/toastify-js/src/toastify.min.css">

    <style>
        :root { --sidebar-width: 260px; }
        
        body { 
            background-color: #121212; 
            color: #e0e0e0; 
            height: 100vh; 
            overflow: hidden; 
        }

        /* Sidebar - Dark Theme */
        .sidebar {
            width: var(--sidebar-width); height: 100vh; position: fixed; left: 0; top: 0;
            background: #1e1e1e; border-right: 1px solid #333; padding: 1rem; z-index: 1000; overflow-y: auto;
        }

        /* Main Content Layout */
        .main-content { 
            margin-left: var(--sidebar-width); 
            height: 100vh; 
            display: flex; 
            flex-direction: column; 
        }

        /* Camera Items */
        .camera-item {
            cursor: pointer; padding: 12px; border-radius: 6px; margin-bottom: 8px;
            background: #2c2c2c; transition: all 0.2s; border-left: 3px solid transparent;
        }
        .camera-item:hover { background-color: #383838; }
        .camera-item.active { 
            background-color: #333; 
            border-left-color: #0d6efd; 
            box-shadow: 0 2px 4px rgba(0,0,0,0.2); 
        }

        .status-badge { font-size: 0.7em; padding: 2px 6px; border-radius: 4px; }
        .status-online { background: #198754; color: white; }

        /* Toolbar */
        .toolbar {
            flex-shrink: 0;
            background: #1e1e1e; padding: 10px 20px; border-bottom: 1px solid #333;
            display: flex; justify-content: space-between; align-items: center;
        }

        /* Debug Panel (Top Position) */
        .debug-panel {
            flex-shrink: 0;
            background: #1e1e1e; 
            border-bottom: 1px solid #333; 
            font-family: monospace; font-size: 0.8em; 
            max-height: 30%; 
            overflow-y: auto; 
            padding: 5px 20px;
            z-index: 2000;
        }

        /* Video Stage (Fills remaining space) */
        .video-stage {
            flex-grow: 1; 
            display: flex; 
            align-items: center; 
            justify-content: center;
            background: #000; 
            overflow: hidden; 
            position: relative; 
            padding: 10px;
            min-height: 0; /* Critical for flex shrinking */
        }

        .video-wrapper {
            position: relative; display: inline-block; 
            box-shadow: 0 0 20px rgba(0,0,0,0.5); user-select: none;
            max-width: 100%; max-height: 100%;
        }

        #video-feed { 
            display: block; 
            max-width: 100%; max-height: 100%; 
            object-fit: contain;
            pointer-events: none; 
        }

        /* ROI Overlays */
        #roi-overlay { position: absolute; top: 0; left: 0; right: 0; bottom: 0; z-index: 10; }

        .roi-box {
            position: absolute; border: 2px solid #00ff00;
            background-color: rgba(0, 255, 0, 0.15); cursor: move; box-sizing: border-box;
            transform-origin: center center;
        }
        .roi-box:hover { border-color: #fff; z-index: 100; background-color: rgba(0, 255, 0, 0.25); }
        .roi-box.selected { border-color: #ffc107; z-index: 110; background-color: rgba(255, 193, 7, 0.2); }

        .resize-handle {
            width: 12px; height: 12px; background: #fff; border: 1px solid #000;
            position: absolute; bottom: -6px; right: -6px; cursor: nwse-resize; z-index: 120;
        }
        
        .rotate-handle {
            width: 12px; height: 12px; background: #0d6efd; border: 1px solid #fff; border-radius: 50%;
            position: absolute; top: -20px; left: 50%; transform: translateX(-50%);
            cursor: grab; z-index: 120; display: none;
        }
        .rotate-handle::after {
            content: ''; position: absolute; top: 10px; left: 50%; width: 2px; height: 10px;
            background: #0d6efd; transform: translateX(-1px);
        }
        .roi-box:hover .rotate-handle, .roi-box.selected .rotate-handle { display: block; }

        .delete-roi {
            position: absolute; top: -12px; right: -12px; background: #dc3545; color: white;
            border-radius: 50%; width: 24px; height: 24px; font-size: 14px;
            display: flex; align-items: center; justify-content: center; cursor: pointer; z-index: 120;
            display: none; box-shadow: 0 2px 4px rgba(0,0,0,0.3);
        }
        .roi-box:hover .delete-roi, .roi-box.selected .delete-roi { display: flex; }

        .detection-badge {
            position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%);
            background: rgba(0,0,0,0.8); color: #0f0; font-weight: bold; padding: 2px 6px;
            pointer-events: none; border-radius: 4px; font-size: 1.2em; text-shadow: 0 0 5px #000;
        }
    </style>
</head>
<body>

<div x-data="app()" x-init="initApp()" class="d-flex"
     @mousemove.window="handleGlobalMove($event)"
     @mouseup.window="handleGlobalUp($event)">

    <!-- Sidebar -->
    <div class="sidebar d-flex flex-column">
        <h5 class="mb-4 text-primary fw-bold"><i class="fas fa-microchip me-2"></i>EdgeAI Monitor</h5>
        
        <div class="mb-3 flex-grow-1 overflow-auto">
            <label class="small text-muted mb-2 text-uppercase fw-bold" style="font-size: 0.7em; letter-spacing: 1px;">Cameras</label>
            <div x-show="cameras.length === 0" class="text-muted small text-center py-4">
                <i class="fas fa-spinner fa-spin mb-2"></i><br>Loading...
            </div>
            
            <template x-for="cam in cameras" :key="cam.id">
                <div class="camera-item" 
                     :class="{'active': currentCamera && currentCamera.id === cam.id}" 
                     @click="selectCamera(cam)">
                    <div class="d-flex justify-content-between align-items-center mb-1">
                        <span class="fw-bold text-white" x-text="cam.name"></span>
                        <span class="status-badge status-online">LIVE</span>
                    </div>
                    <div class="small text-muted font-monospace" x-text="cam.id" style="font-size: 0.8em"></div>
                </div>
            </template>
        </div>

        <div class="mt-auto pt-3 border-top border-secondary">
            <div class="d-grid gap-2">
                <button class="btn btn-outline-secondary btn-sm text-light" @click="loadROIs()" :disabled="!currentCamera">
                    <i class="fas fa-sync me-2"></i>Reload ROIs
                </button>
                <button class="btn btn-primary btn-sm" @click="saveROIs()" :disabled="!currentCamera">
                    <i class="fas fa-save me-2"></i>Save Config
                </button>
            </div>
        </div>
    </div>

    <!-- Main Content -->
    <div class="main-content flex-grow-1">
        
        <!-- Empty State -->
        <div x-show="!currentCamera" class="h-100 d-flex flex-column justify-content-center align-items-center text-secondary">
            <i class="fas fa-video fa-3x mb-3"></i>
            <h3>Select a Camera</h3>
            <p>Choose a stream from the sidebar to begin.</p>
        </div>

        <!-- Camera View -->
        <div x-show="currentCamera" class="d-flex flex-column h-100">
            
            <!-- 1. Top Toolbar -->
            <div class="toolbar">
                <div class="d-flex align-items-center gap-3">
                    <h5 class="m-0 text-white" x-text="currentCamera ? currentCamera.name : ''"></h5>
                    
                    <!-- Flip Controls -->
                    <div class="btn-group btn-group-sm">
                        <button class="btn btn-outline-secondary" @click="rotateFlip('none')" title="Normal"><i class="fas fa-arrow-up"></i></button>
                        <button class="btn btn-outline-secondary" @click="rotateFlip('horizontal')" title="Flip Horizontal"><i class="fas fa-arrows-alt-h"></i></button>
                        <button class="btn btn-outline-secondary" @click="rotateFlip('vertical')" title="Flip Vertical"><i class="fas fa-arrows-alt-v"></i></button>
                        <button class="btn btn-outline-secondary" @click="rotateFlip('both')" title="Flip Both"><i class="fas fa-compress-arrows-alt"></i></button>
                    </div>

                    <!-- Aspect Ratio Toggle -->
                    <div class="form-check form-switch ms-3 text-white small m-0">
                        <input class="form-check-input" type="checkbox" id="lockRatio" x-model="lockRatio">
                        <label class="form-check-label" for="lockRatio">Lock 20:32</label>
                    </div>
                </div>

                <div class="d-flex align-items-center">
                    <span class="badge bg-secondary me-3">ROIs: <span x-text="rois.length"></span></span>
                    
                    <button class="btn btn-outline-light btn-sm me-2" @click="takeSnapshot()">
                        <i class="fas fa-camera"></i>
                    </button>
                    <button class="btn btn-success btn-sm" @click="testDetection()">
                        <i class="fas fa-play me-2"></i>Test
                    </button>
                </div>
            </div>

            <!-- 2. Debug Panel (Top Position) -->
            <div class="debug-panel">
                <button class="btn btn-link btn-sm text-secondary p-0 text-decoration-none" @click="showDebug = !showDebug">
                    <i class="fas" :class="showDebug ? 'fa-chevron-down' : 'fa-chevron-right'"></i> Debug JSON
                </button>
                <div x-show="showDebug" class="mt-2">
                    <pre class="m-0 text-info" x-text="getDebugJSON()"></pre>
                </div>
            </div>

            <!-- 3. Video Stage (Fills Rest) -->
            <div class="video-stage">
                <div class="video-wrapper" 
                     x-ref="videoWrapper"
                     @mousedown="startDraw($event)">
                    
                    <img :src="videoUrl" id="video-feed" 
                         x-ref="videoImg"
                         @load="onImageLoad">

                    <div id="roi-overlay">
                        <template x-for="(roi, index) in rois" :key="roi.id">
                            <div class="roi-box" 
                                 :class="{'selected': selectedRoiId === roi.id}"
                                 :style="`left: ${roi.x}px; top: ${roi.y}px; width: ${roi.width}px; height: ${roi.height}px; transform: rotate(${roi.angle || 0}deg);`"
                                 @mousedown.stop="startMove(roi.id, $event)">
                                 
                                <div class="delete-roi" @mousedown.stop="deleteRoi(index)"><i class="fas fa-times"></i></div>
                                <div class="resize-handle" @mousedown.stop="startResize(index, $event)"></div>
                                <div class="rotate-handle" @mousedown.stop="startRotate(index, $event)"></div>

                                <div class="detection-badge" x-show="roi.lastValue !== undefined" x-text="roi.lastValue" :style="`transform: rotate(-${roi.angle || 0}deg);`"></div>
                                <div class="position-absolute top-0 start-0 text-white bg-primary px-1" style="font-size:10px" x-text="index+1"></div>
                            </div>
                        </template>

                        <div x-show="interactionMode === 'drawing'" class="roi-box" 
                             style="border-style: dashed; pointer-events: none;"
                             :style="`left: ${drawBox.x}px; top: ${drawBox.y}px; width: ${drawBox.w}px; height: ${drawBox.h}px;`">
                        </div>
                    </div>
                </div>
            </div>

        </div>
    </div>
</div>

<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/alpinejs@3.x.x/dist/cdn.min.js" defer></script>
<script src="https://cdn.jsdelivr.net/npm/toastify-js"></script>

<script>
    document.addEventListener('alpine:init', () => {
        Alpine.data('app', () => ({
            cameras: [],
            currentCamera: null,
            videoUrl: '',
            rois: [],
            selectedRoiId: null,
            showDebug: false,
            
            // Interaction State
            interactionMode: null, // 'drawing', 'moving', 'resizing', 'rotating'
            activeRoiIndex: -1,
            dragStart: {x:0, y:0},
            drawStart: {x:0, y:0},
            drawBox: {x:0, y:0, w:0, h:0},
            lockRatio: true,
            imgReady: false,

            async initApp() { await this.fetchCameras(); },
            async fetchCameras() {
                try {
                    const res = await fetch('/cameras');
                    this.cameras = await res.json();
                } catch(e) {}
            },
            selectCamera(cam) {
                this.currentCamera = cam;
                this.rois = [];
                this.imgReady = false; // Reset on switch
                this.videoUrl = `/video/${cam.id}?t=${Date.now()}`;
            },
            onImageLoad(e) {
                const w = e.target.clientWidth;
                const h = e.target.clientHeight;
                this.imgReady = true; // <--- TRIGGER UPDATE
                if(this.currentCamera) this.loadROIs(w, h);
            },
            async loadROIs(w, h) {
                if(!w || !h) {
                     const img = this.$refs.videoImg;
                     if(img) { w=img.clientWidth; h=img.clientHeight; } else { w=640; h=360; }
                }
                try {
                    const res = await fetch(`/rois/${this.currentCamera.id}?img_width=${w}&img_height=${h}`);
                    const data = await res.json();
                    if(Array.isArray(data)) {
                        this.rois = data.map(r => ({
                            id: r.id || Date.now().toString(),
                            x: Number(r.x), y: Number(r.y), width: Number(r.width), height: Number(r.height),
                            angle: Number(r.angle || 0), lastValue: undefined
                        }));
                    }
                } catch(e) {}
            },
            async saveROIs() {
                const img = this.$refs.videoImg;
                if(!img) return;
                try {
                    const res = await fetch('/save_rois', {
                        method: 'POST',
                        headers: {'Content-Type': 'application/json'},
                        body: JSON.stringify({
                            camera_id: this.currentCamera.id,
                            rois: this.rois,
                            img_width: img.clientWidth,
                            img_height: img.clientHeight
                        })
                    });
                    const d = await res.json();
                    if(d.success) this.showToast("Saved!", "success");
                    else this.showToast("Save Failed: " + d.error, "error");
                } catch(e) { this.showToast("Network Error", "error"); }
            },
            async rotateFlip(type) {
                await fetch('/update_camera_config', { method: 'POST', headers: {'Content-Type':'application/json'}, body: JSON.stringify({camera_id: this.currentCamera.id, flip_type: type})});
                this.selectCamera(this.currentCamera);
            },
            async takeSnapshot() { if(this.currentCamera) window.open(`/snapshot/${this.currentCamera.id}`, '_blank'); },
            async testDetection() {
                this.showToast("Scanning...", "info");
                try {
                    const res = await fetch('/detect_digits', { method: 'POST', headers: {'Content-Type':'application/json'}, body: JSON.stringify({camera_id: this.currentCamera.id})});
                    const d = await res.json();
                    if(d.detected_digits) {
                        d.detected_digits.forEach((val, i) => { if(this.rois[i]) this.rois[i].lastValue = val; });
                        this.showToast(`Read: ${d.final_number}`, "success");
                    } else if(d.error) { this.showToast(d.error, "error"); }
                } catch(e) {}
            },

            // --- COMPUTED DEBUG ---
            getDebugJSON() {
                if(!this.imgReady) return "Loading image data...";
                
                const img = this.$refs.videoImg;
                if(!img || !img.naturalWidth) return "Waiting for stream...";

                const scaleX = img.naturalWidth / img.clientWidth;
                const scaleY = img.naturalHeight / img.clientHeight;
                
                const report = this.rois.map(r => ({
                    id: r.id,
                    display: { x: Math.round(r.x), y: Math.round(r.y), w: Math.round(r.width), h: Math.round(r.height) },
                    real: { 
                        x: Math.round(r.x * scaleX), 
                        y: Math.round(r.y * scaleY), 
                        w: Math.round(r.width * scaleX), 
                        h: Math.round(r.height * scaleY) 
                    },
                    angle: Math.round(r.angle || 0)
                }));
                return JSON.stringify(report, null, 2);
            },

            // --- INTERACTION ---
            getRelPos(e) {
                const rect = this.$refs.videoWrapper.getBoundingClientRect();
                return { x: e.clientX - rect.left, y: e.clientY - rect.top };
            },
            startDraw(e) {
                const pos = this.getRelPos(e);
                this.interactionMode = 'drawing';
                this.drawStart = pos;
                this.drawBox = {x: pos.x, y: pos.y, w:0, h:0};
                this.selectedRoiId = null;
            },
            startMove(id, e) {
                this.selectedRoiId = id;
                this.activeRoiIndex = this.rois.findIndex(r => r.id === id);
                this.interactionMode = 'moving';
                this.dragStart = {x: e.clientX, y: e.clientY};
            },
            startResize(index, e) {
                this.activeRoiIndex = index;
                this.interactionMode = 'resizing';
                this.dragStart = {x: e.clientX, y: e.clientY};
            },
            startRotate(index, e) {
                this.activeRoiIndex = index;
                this.interactionMode = 'rotating';
                this.dragStart = {x: e.clientX, y: e.clientY};
            },
            handleGlobalMove(e) {
                if (!this.interactionMode) return;
                
                if (this.interactionMode === 'drawing') {
                    const pos = this.getRelPos(e);
                    let w = pos.x - this.drawStart.x;
                    let h = pos.y - this.drawStart.y;
                    
                    if(this.lockRatio) {
                         const signW = Math.sign(w) || 1;
                         const signH = Math.sign(h) || 1;
                         const absW = Math.abs(w);
                         const targetRatio = 20/32;
                         w = absW * signW;
                         h = (absW / targetRatio) * signH;
                    }
                    this.drawBox = { x: w<0?pos.x:this.drawStart.x, y: h<0?pos.y:this.drawStart.y, w: Math.abs(w), h: Math.abs(h) };
                }
                else if (this.interactionMode === 'moving' && this.activeRoiIndex > -1) {
                    const dx = e.clientX - this.dragStart.x;
                    const dy = e.clientY - this.dragStart.y;
                    const roi = this.rois[this.activeRoiIndex];
                    roi.x += dx; roi.y += dy;
                    this.dragStart = {x: e.clientX, y: e.clientY};
                }
                else if (this.interactionMode === 'resizing' && this.activeRoiIndex > -1) {
                    const dx = e.clientX - this.dragStart.x;
                    const dy = e.clientY - this.dragStart.y;
                    const roi = this.rois[this.activeRoiIndex];
                    let newW = Math.max(10, roi.width + dx);
                    let newH = Math.max(10, roi.height + dy);
                    
                    if(this.lockRatio) {
                         const targetRatio = 20/32;
                         newH = newW / targetRatio;
                    }
                    roi.width = newW; roi.height = newH;
                    this.dragStart = {x: e.clientX, y: e.clientY};
                }
                else if (this.interactionMode === 'rotating' && this.activeRoiIndex > -1) {
                    const dx = e.clientX - this.dragStart.x;
                    const roi = this.rois[this.activeRoiIndex];
                    roi.angle = (roi.angle || 0) + (dx * 0.5);
                    this.dragStart = {x: e.clientX, y: e.clientY};
                }
            },
            handleGlobalUp(e) {
                if (this.interactionMode === 'drawing' && this.drawBox.w > 10 && this.drawBox.h > 10) {
                    this.rois.push({
                        id: Date.now().toString(),
                        x: Math.round(this.drawBox.x), y: Math.round(this.drawBox.y),
                        width: Math.round(this.drawBox.w), height: Math.round(this.drawBox.h),
                        angle: 0
                    });
                }
                this.interactionMode = null;
                this.activeRoiIndex = -1;
            },
            deleteRoi(index) { if(confirm("Delete ROI?")) this.rois.splice(index, 1); },
            showToast(msg, type="info") { Toastify({ text: msg, duration: 2000, style: { background: type=="error"?"#dc3545":"#198754" } }).showToast(); }
        }));
    });
</script>
</body>
</html>
