import cv2
import telebot
import numpy as np
import threading
import time
import os
from datetime import datetime

# --- OPTIMASI KONEKSI ---
os.environ["OPENCV_FFMPEG_CAPTURE_OPTIONS"] = "timeout;5000000"

# --- KONFIGURASI ---
TOKEN = "8644696872:AAFNzBEBwWpR0V7r6rP3dYwWCyokE2WQNyo"
CHAT_ID = "275595749"
CCTV_URL = "https://dishub.pasuruankab.go.id:5444/LiveApp/streams/SEMAMBUNG.m3u8"

PROTOTXT = "MobileNetSSD_deploy.prototxt"
MODEL = "MobileNetSSD_deploy.caffemodel"

CLASSES = ["background", "aeroplane", "bicycle", "bird", "boat",
           "bottle", "bus", "car", "cat", "chair", "cow", "diningtable",
           "dog", "horse", "motorbike", "person", "pottedplant", "sheep",
           "sofa", "train", "tvmonitor"]

# --- SETTING AREA SCAN (ROI) ---
Y_START, Y_END = 90, 360
X_START, X_END = 0, 640

bot = telebot.TeleBot(TOKEN)
net = cv2.dnn.readNetFromCaffe(PROTOTXT, MODEL)

current_frame = None
streaming_active = False

def send_photo_with_retry(photo_buffer, caption, max_retries=3):
    """Fungsi khusus untuk mengirim foto dengan fitur coba ulang jika koneksi error"""
    for attempt in range(max_retries):
        try:
            bot.send_photo(CHAT_ID, photo_buffer, caption=caption, parse_mode="Markdown", timeout=20)
            print(f"[{datetime.now().strftime('%H:%M:%S')}] Objek terkirim ke Telegram.")
            return True
        except Exception as e:
            print(f" Percobaan {attempt+1} gagal: {e}")
            if attempt < max_retries - 1:
                time.sleep(2) # Jeda sebelum coba lagi
            else:
                print(" !!! Gagal mengirim foto setelah beberapa kali mencoba.")
    return False

def stream_worker():
    global current_frame, streaming_active
    cap = None
    
    while True:
        sekarang = datetime.now()
        # Jam operasional deteksi otomatis
        if 10 <= sekarang.hour <= 14:
            if cap is None or not cap.isOpened():
                print(f"[{sekarang.strftime('%H:%M')}] Menghubungkan ke CCTV...")
                cap = cv2.VideoCapture(CCTV_URL)
                streaming_active = True
            
            ret, frame = cap.read()
            if ret:
                current_frame = frame
            else:
                print(" Gagal baca frame CCTV, mencoba ulang...")
                if cap: cap.release()
                cap = None
                time.sleep(5)
        else:
            if streaming_active:
                print(f"[{sekarang.strftime('%H:%M')}] Standby (Luar jam operasional)...")
                if cap: cap.release()
                cap = None
                streaming_active = False
                current_frame = None
            time.sleep(30)
        time.sleep(0.01)

def deteksi_bis_loop():
    print("Sistem AI Deteksi Aktif dengan Auto-Retry...")
    last_sent_time = 0
    min_confidence = 0.4 # Sedikit dinaikkan agar lebih akurat
    cooldown_kirim = 3

    while True:
        if streaming_active and current_frame is not None:
            img = current_frame.copy()
            roi = img[Y_START:Y_END, X_START:X_END]
            (h_roi, w_roi) = roi.shape[:2]

            blob = cv2.dnn.blobFromImage(cv2.resize(roi, (300, 300)), 0.007843, (300, 300), 127.5)
            net.setInput(blob)
            detections = net.forward()

            for i in range(0, detections.shape[2]):
                confidence = detections[0, 0, i, 2]
                if confidence > min_confidence:
                    idx = int(detections[0, 0, i, 1])
                    if CLASSES[idx] == "bus":
                        current_time = time.time()
                        if current_time - last_sent_time > cooldown_kirim:
                            # Kalkulasi Box
                            box = detections[0, 0, i, 3:7] * np.array([w_roi, h_roi, w_roi, h_roi])
                            (sX, sY, eX, eY) = box.astype("int")
                            
                            # Gambar kotak di koordinat yang benar (tambah offset Y_START)
                            cv2.rectangle(img, (sX + X_START, sY + Y_START), (eX + X_START, eY + Y_START), (0, 255, 0), 2)
                            
                            _, buffer = cv2.imencode('.jpg', img)
                            caption_msg = f"🚌 *KENDARAAN TERDETEKSI*\nWaktu: {datetime.now().strftime('%H:%M:%S')}\nConfidence: {confidence*100:.1f}%"
                            
                            # Gunakan fungsi retry
                            if send_photo_with_retry(buffer.tobytes(), caption_msg):
                                last_sent_time = current_time
        
        time.sleep(0.5) # Sampling interval

@bot.message_handler(commands=['cek'])
def manual_cek(message):
    bot.send_chat_action(message.chat.id, 'upload_photo')
    if streaming_active and current_frame is not None:
        _, buffer = cv2.imencode('.jpg', current_frame)
        send_photo_with_retry(buffer.tobytes(), "📸 Cek Manual (Live Stream)")
    else:
        bot.send_message(message.chat.id, "🔄 Membuka koneksi sementara...")
        temp_cap = cv2.VideoCapture(CCTV_URL)
        time.sleep(2)
        success, frame = temp_cap.read()
        if success:
            _, buffer = cv2.imencode('.jpg', frame)
            send_photo_with_retry(buffer.tobytes(), "📸 Cek Manual (On-Demand)")
        else:
            bot.send_message(message.chat.id, "❌ Gagal mengambil gambar dari CCTV.")
        temp_cap.release()

if __name__ == "__main__":
    threading.Thread(target=stream_worker, daemon=True).start()
    threading.Thread(target=deteksi_bis_loop, daemon=True).start()
    
    print("--- BOT CCTV SIAP ---")
    
    while True:
        try:
            bot.infinity_polling(timeout=60, long_polling_timeout=30)
        except Exception as e:
            print(f"Polling error: {e}")
            time.sleep(5)