import cv2
import sqlite3
import time
import os
import threading
import queue
import tkinter as tk
from tkinter import messagebox, filedialog, simpledialog  # <-- ADIÇÃO
from PIL import Image, ImageTk, ImageDraw, ImageFont
import torch
from ultralytics import YOLO
import pygame
import yt_dlp
import sys
import platform

# --- IMPORTS PARA PDF (ReportLab) ---
from reportlab.lib.pagesizes import letter
from reportlab.pdfgen import canvas
from reportlab.lib import colors
from reportlab.platypus import SimpleDocTemplate, Table, TableStyle, Paragraph, Spacer
from reportlab.lib.styles import getSampleStyleSheet
from reportlab.lib.units import inch

# ----------------------------------------------------
# --- CONFIGURAÇÕES GLOBAIS (Compartilhadas) ---
# ----------------------------------------------------
DB_NAME = 'skyhawk_auto.db'
FRAME_SKIP = 3  # Processa 1 quadro a cada 3 capturados (OTIMIZAÇÃO DE PERFORMANCE)
IMG_SIZE = 640
ALARM_FILE = "finland_alarm.mp3"

# --- CONFIGURAÇÃO DOS LOGOTIPOS ---
LOGO_ESQUERDA = "skyhawk_logo.png"
LOGO_DIREITA = "inviolavel.png"

# --- LINK ALVO PADRÃO ---
TARGET_URL = "https://youtube.com/live/VkA1QKzwZvc?feature=share"

# Caminho do modelo
MODEL_PATH = r'C:\Users\Public\DroneHeatmap\pythonProject\treinov8m.pt'
FONT_PATH = "arial.ttf"  # Fonte para Overlay.

# Credenciais fixas (Pode ser alterado para leitura de arquivo/DB)
USUARIO_PADRAO = 'admin'
SENHA_PADRAO = '123'

# --- CONFIGURAÇÃO VISUAL LOGIN ---
BG_COLOR = '#2C3E50'
FG_COLOR = 'white'
ACCENT_COLOR = '#3498DB'
FONT_STYLE = ('Arial', 10)


# ----------------------------------------------------

# --- CLASSE DE GESTÃO DE BANCO DE DADOS ---
class DatabaseManager:
    def __init__(self, db_name):
        self.db_name = db_name
        self.init_db()

    def init_db(self):
        with sqlite3.connect(self.db_name) as conn:
            conn.execute('''CREATE TABLE IF NOT EXISTS detection_data (
                            id INTEGER PRIMARY KEY AUTOINCREMENT,
                            track_id INTEGER,
                            data TEXT NOT NULL, 
                            timestamp REAL)''')

    def insert_event(self, track_id, detail):
        try:
            with sqlite3.connect(self.db_name) as conn:
                ts = time.time()
                conn.execute('INSERT INTO detection_data (track_id, data, timestamp) VALUES (?, ?, ?)',
                             (track_id, detail, ts))
            return True
        except Exception as e:
            print(f"Erro DB: {e}")
            return False

    def get_all(self):
        with sqlite3.connect(self.db_name) as conn:
            return conn.execute(
                "SELECT track_id, data, timestamp FROM detection_data ORDER BY timestamp DESC").fetchall()

    def clear_all(self):
        with sqlite3.connect(self.db_name) as conn:
            conn.execute("DELETE FROM detection_data")


# --- CLASSE PARA CABEÇALHO E RODAPÉ DO PDF ---
class PDFHeaderFooter(canvas.Canvas):
    def __init__(self, *args, **kwargs):
        canvas.Canvas.__init__(self, *args, **kwargs)
        self.pages = []
        self.width, self.height = letter

    def showPage(self):
        self.pages.append(dict(self.__dict__))
        self._startPage()

    def save(self):
        page_count = len(self.pages)
        for page in self.pages:
            self.__dict__.update(page)
            self.draw_elements(page_count)
            canvas.Canvas.showPage(self)
        canvas.Canvas.save(self)

    def draw_elements(self, page_count):
        # 1. Logo ESQUERDA
        if os.path.exists(LOGO_ESQUERDA):
            try:
                self.drawImage(LOGO_ESQUERDA, 0.5 * inch, self.height - 1.2 * inch,
                               width=1.2 * inch, height=0.9 * inch, preserveAspectRatio=True)
            except Exception:
                pass

        # 2. Logo DIREITA
        if os.path.exists(LOGO_DIREITA):
            try:
                pos_x = self.width - 1.7 * inch
                self.drawImage(LOGO_DIREITA, pos_x, self.height - 1.2 * inch,
                               width=1.2 * inch, height=0.9 * inch, preserveAspectRatio=True, anchor='ne')
            except Exception:
                pass

        # 3. Linha Separadora
        self.setLineWidth(2)
        self.line(0.5 * inch, self.height - 1.3 * inch, self.width - 0.5 * inch, self.height - 1.3 * inch)

        # 4. Rodapé
        self.setFont('Helvetica', 9)
        self.drawRightString(self.width - 0.5 * inch, 0.5 * inch, f"Página {self._pageNumber}")


# --- CLASSE PRINCIPAL DO APLICATIVO (SkyHawk) ---
class SkyHawkAuto:
    def __init__(self, root, login_callback):
        self.root = root
        self.db = DatabaseManager(DB_NAME)
        self.db.clear_all()
        self.login_callback = login_callback

        self.model = None
        self.cap = None
        self.running = False
        self.thread = None
        # Fila de tamanho 1 para garantir que o frame mais novo seja exibido (OTIMIZAÇÃO)
        self.frame_queue = queue.Queue(maxsize=1)
        self.logged_ids = set()
        self.detected_count = 0
        self.session_start_ts = None
        self.session_end_ts = None
        self.detection_log = []

        # VARIÁVEL PARA O ALVO ATUAL (STREAM OU ARQUIVO) <-- ADIÇÃO
        self.current_target_url = TARGET_URL

        pygame.mixer.init()
        self.setup_ui()
        self.load_model()

        # Inicia a tentativa de stream (apenas uma vez)
        self.root.after(1000, self.start_auto_stream)
        self.update_ui_loop()

        self.root.protocol("WM_DELETE_WINDOW", self.on_close)

    def setup_ui(self):

        self.root.title("Monitoramento Híbrido (MAXIMIZADO)")
        self.root.configure(bg='#000000')

        if platform.system() == "Windows":
            self.root.state('zoomed')
        else:
            self.root.attributes('-fullscreen', True)

        self.root.update_idletasks()
        screen_width = self.root.winfo_width()
        screen_height = self.root.winfo_height()

        PADDING_H = 20
        PADDING_V = 60
        SIDE_PANEL_WIDTH = 0

        self.display_w = screen_width - PADDING_H - SIDE_PANEL_WIDTH
        self.display_h = screen_height - PADDING_V - 40

        content_frame = tk.Frame(self.root, bg='black')
        content_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)

        self.canvas = tk.Canvas(content_frame, width=self.display_w, height=self.display_h, bg="#111",
                                highlightthickness=0)
        self.canvas.pack(side=tk.TOP, fill=tk.BOTH, expand=True, padx=(0, 10))

        self.lbl_status = tk.Label(content_frame, text="Aguardando conexão...", bg="black", fg="#00FF00",
                                   font=("Consolas", 10))
        self.lbl_status.pack(pady=(5, 0), fill=tk.X)

        button_frame = tk.Frame(content_frame, bg='black')
        button_frame.pack(pady=(5, 0), fill=tk.X)

        # 1. Botão de ENCERRAMENTO com Relatório
        btn_stop = tk.Button(button_frame,
                             text="ENCERRAR TRANSMISSÃO E RELATÓRIO",
                             command=self.stop_and_report,
                             bg='#E74C3C',
                             fg='white',
                             font=('Arial', 10, 'bold'))
        btn_stop.pack(side=tk.LEFT, expand=True, fill=tk.X, padx=(0, 5), ipady=5)

        # 2. BOTÃO: SAIR E VOLTAR AO LOGIN
        btn_exit = tk.Button(button_frame,
                             text="SAIR E VOLTAR AO LOGIN",
                             command=self.exit_to_login,
                             bg='#34495E',
                             fg='white',
                             font=('Arial', 10, 'bold'))
        btn_exit.pack(side=tk.LEFT, expand=True, fill=tk.X, padx=(5, 5), ipady=5)  # <-- MUDANÇA NO padx

        # 3. BOTÃO: CARREGAR VÍDEO LOCAL (TESTE) <-- ADIÇÃO
        btn_load_video = tk.Button(button_frame,
                                   text="VÍDEO LOCAL (TESTE)",
                                   command=self._load_local_video,
                                   bg='#3498DB',
                                   fg='white',
                                   font=('Arial', 10, 'bold'))
        btn_load_video.pack(side=tk.LEFT, expand=True, fill=tk.X, padx=(5, 5), ipady=5)

        # 4. BOTÃO: INSERIR NOVA URL <-- ADIÇÃO
        btn_new_url = tk.Button(button_frame,
                                text="INSERIR NOVA URL",
                                command=self._prompt_stream_url,
                                bg='#1ABC9C',
                                fg='white',
                                font=('Arial', 10, 'bold'))
        btn_new_url.pack(side=tk.LEFT, expand=True, fill=tk.X, padx=(5, 0), ipady=5)

        try:
            self.overlay_font_large = ImageFont.truetype(FONT_PATH, 16)
            self.overlay_font_small = ImageFont.truetype(FONT_PATH, 11)
            self.overlay_font_medium = ImageFont.truetype(FONT_PATH, 12)
        except IOError:
            self.overlay_font_large = ImageFont.load_default()
            self.overlay_font_small = ImageFont.load_default()
            self.overlay_font_medium = ImageFont.load_default()

    def log(self, msg):
        print(f"[SkyHawk] {msg}")
        self.lbl_status.config(text=msg)

    def load_model(self):
        try:
            self.log(f"Carregando modelo...")
            device = 'cuda' if torch.cuda.is_available() else 'cpu'

            if not os.path.exists(MODEL_PATH):
                self.log("Modelo custom não encontrado. Usando yolov8n.pt.")
                self.model = YOLO('yolov8n.pt').to(device)
            else:
                self.model = YOLO(MODEL_PATH).to(device)

            self.log(f"Modelo carregado. Dispositivo: {device.upper()}")
        except Exception as e:
            self.log(f"Erro Modelo: {e}")

    def play_alarm(self):
        def _play():
            if os.path.exists(ALARM_FILE):
                try:
                    pygame.mixer.music.load(ALARM_FILE)
                    pygame.mixer.music.play()
                except Exception:
                    pass

        threading.Thread(target=_play, daemon=True).start()

    def get_stream_url(self, target_url):
        """Tenta extrair a URL de stream, especialmente para YouTube."""
        final_url = target_url
        if "youtube.com" in target_url or "youtu.be" in target_url:
            self.log("Link YouTube detectado. Tentando extrair stream...")
            try:
                ydl_opts = {'format': 'best', 'quiet': True, 'no_warnings': True}
                with yt_dlp.YoutubeDL(ydl_opts) as ydl:
                    info = ydl.extract_info(target_url, download=False)
                    formats = info.get('formats', [])
                    url_found = next(
                        (f['url'] for f in formats if f.get('ext') == 'mp4' and f.get('protocol') in ('https', 'http')),
                        info.get('url'))
                    final_url = url_found
                self.log("Stream extraída com sucesso.")
                return final_url
            except Exception as e:
                self.log(f"Erro yt-dlp: {e}")
                return None
        elif os.path.exists(target_url):
            self.log("Caminho de arquivo local detectado.")
            return target_url
        else:
            self.log("Link Direto detectado (RTSP/RTMP/HTTP).")
            return final_url

    def _restart_stream(self):  # <-- ADIÇÃO DO MÉTODO
        """Método auxiliar para limpar e iniciar uma nova stream/vídeo."""
        if self.running:
            self._cleanup_video_thread()
            # O clean-up destrói o CAP e seta running=False

        # Reseta os logs para a nova sessão
        self.db.clear_all()
        self.logged_ids = set()
        self.detected_count = 0
        self.session_start_ts = None
        self.session_end_ts = None
        self.detection_log = []

        self.start_auto_stream(restart=True)

    def _load_local_video(self):  # <-- ADIÇÃO DO MÉTODO
        """Permite ao usuário carregar um arquivo de vídeo local."""
        if self.running and not messagebox.askyesno("Trocar Stream",
                                                    "Uma transmissão está ativa. Deseja encerrá-la e carregar um vídeo local?"):
            return

        file_path = filedialog.askopenfilename(
            title="Selecione um Arquivo de Vídeo para Teste",
            filetypes=(("Arquivos de Vídeo", "*.mp4;*.avi;*.mov"), ("Todos os Arquivos", "*.*"))
        )

        if file_path:
            self.current_target_url = file_path
            self.log(f"Novo alvo: Arquivo Local: {os.path.basename(file_path)}")
            self._restart_stream()

    def _prompt_stream_url(self):  # <-- ADIÇÃO DO MÉTODO
        """Permite ao usuário inserir uma nova URL de stream."""
        if self.running and not messagebox.askyesno("Trocar Stream",
                                                    "Uma transmissão está ativa. Deseja encerrá-la e inserir uma nova URL?"):
            return

        new_url = simpledialog.askstring("Nova URL de Stream", "Insira a nova URL (Ex: YouTube, RTSP, etc.):",
                                         parent=self.root, initialvalue=self.current_target_url)

        if new_url and new_url != self.current_target_url:
            self.current_target_url = new_url
            self.log(f"Novo alvo: URL de Stream: {self.current_target_url}")
            self._restart_stream()
        elif new_url:
            self.log("URL de Stream inalterada.")

    def start_auto_stream(self, restart=False):  # <-- MUDANÇA NA ASSINATURA E LÓGICA
        """Tenta iniciar a conexão UMA ÚNICA VEZ (ou após restart)."""
        if self.running and not restart:
            return

        stream_url = self.get_stream_url(self.current_target_url)  # <-- USO DA VARIÁVEL DE INSTÂNCIA

        if stream_url:
            # Tenta abrir o cap com a URL
            self.cap = cv2.VideoCapture(stream_url, cv2.CAP_FFMPEG)

            if self.cap.isOpened():
                # Sucesso na conexão
                self.running = True
                self.session_start_ts = time.time()
                self.thread = threading.Thread(target=self.video_loop, daemon=True)
                self.thread.start()
                self.log("MONITORAMENTO ATIVO")
            else:
                # Falha na conexão
                if self.cap:
                    self.cap.release()
                self.log("ERRO: Falha ao abrir a URL (Stream Off-line ou link inválido).")
                messagebox.showerror("Erro Conexão",
                                     f"Não foi possível conectar a:\n{self.current_target_url}\nA stream pode estar off-line.")  # <-- USO DA VARIÁVEL DE INSTÂNCIA

        else:
            # Falha ao extrair a URL
            self.log("ERRO: Falha crítica ao extrair URL da stream.")
            messagebox.showerror("Erro Crítico",
                                 f"Falha crítica ao extrair URL da stream:\n{self.current_target_url}")  # <-- USO DA VARIÁVEL DE INSTÂNCIA

    def video_loop(self):
        frame_count = 0
        last_results = None

        while self.running and self.cap.isOpened():
            ret, frame = self.cap.read()
            if not ret:
                self.log("Sinal de vídeo perdido ou fim da stream. Encerrando monitoramento...")
                # Sai do loop e aciona a parada (Sem reconexão)
                self.root.after(0, lambda: self._handle_stream_loss())
                break

            frame_count += 1
            h, w = frame.shape[:2]

            scale = IMG_SIZE / max(h, w)
            nh, nw = int(h * scale), int(w * scale)

            if frame_count % FRAME_SKIP == 0 or last_results is None:
                frame_resized = cv2.resize(frame, (nw, nh), interpolation=cv2.INTER_LINEAR)

            if frame_count % FRAME_SKIP == 0:
                try:
                    results = self.model.track(frame_resized, persist=True, conf=0.25, classes=[0], verbose=False,
                                               tracker="bytetrack.yaml", half=True)
                    last_results = results

                    for result in results:
                        if result.boxes and result.boxes.id is not None:
                            ids = result.boxes.id.cpu().numpy().astype(int)
                            for track_id in ids:
                                if track_id not in self.logged_ids:
                                    self.logged_ids.add(track_id)
                                    self.detected_count += 1

                                    detail_str = "Detecção de Pessoa"
                                    timestamp_str = time.strftime('%H:%M:%S')

                                    self.detection_log.insert(0, (track_id, timestamp_str))
                                    if len(self.detection_log) > 10:
                                        self.detection_log.pop()

                                    self.db.insert_event(int(track_id), detail_str)
                                    self.play_alarm()

                except Exception as e:
                    print(f"Erro Inferência: {e}")

            # --- RENDERIZAÇÃO ---
            if last_results:
                self.model.names[0] = 'Pessoa'
                res_plotted = last_results[0].plot(img=frame_resized.copy())
            else:
                res_plotted = cv2.resize(frame, (nw, nh), interpolation=cv2.INTER_LINEAR)

            img_rgb = cv2.cvtColor(res_plotted, cv2.COLOR_BGR2RGB)
            img_pil = Image.fromarray(img_rgb).resize((self.display_w, self.display_h), Image.Resampling.LANCZOS)

            # --- OVERLAYS NO PIL IMAGE ---
            draw = ImageDraw.Draw(img_pil)

            current_time_str = time.strftime('%d/%m/%Y %H:%M:%S')
            draw.text((20, 20), "INVIOLÁVEL PONTA GROSSA", fill="white", font=self.overlay_font_large)
            draw.text((20, 45), current_time_str, fill="white", font=self.overlay_font_small)

            text_det_count = f"Detecções: {self.detected_count}"
            w_text = draw.textlength(text_det_count, font=self.overlay_font_large)
            draw.text((self.display_w - w_text - 20, self.display_h - 40), text_det_count, fill="#00FF00",
                      font=self.overlay_font_large)

            if self.detection_log:
                BOX_WIDTH = 250
                BOX_HEIGHT = 180
                MARGIN = 15

                box_x1 = self.display_w - BOX_WIDTH - MARGIN
                box_y1 = MARGIN
                box_x2 = self.display_w - MARGIN
                box_y2 = MARGIN + BOX_HEIGHT

                overlay = Image.new('RGBA', img_pil.size, (0, 0, 0, 0))
                draw_overlay = ImageDraw.Draw(overlay)
                draw_overlay.rectangle([box_x1, box_y1, box_x2, box_y2], fill=(0, 0, 0, 150))
                img_pil = Image.alpha_composite(img_pil.convert('RGBA'), overlay)
                draw = ImageDraw.Draw(img_pil)

                draw.text((box_x1 + 10, box_y1 + 5), "ID Pessoa | Hora de Detecção", fill="#FFC300",
                          font=self.overlay_font_medium)

                y_offset = box_y1 + 25
                for track_id, timestamp_str in self.detection_log:
                    line_text = f"{track_id:<9} | {timestamp_str}"
                    draw.text((box_x1 + 10, y_offset), line_text, fill="white", font=self.overlay_font_small)
                    y_offset += 15

            # --- FIM OVERLAYS ---
            img_tk = ImageTk.PhotoImage(image=img_pil)

            while not self.frame_queue.empty():
                self.frame_queue.get_nowait()

            self.frame_queue.put(img_tk)

            time.sleep(0.001)

    def _handle_stream_loss(self):
        """
        Lida com a perda de sinal da stream. Encerra a thread e libera o CAP.
        Sem reconexão.
        """
        self.running = False
        if self.thread and self.thread.is_alive():
            self.thread.join(timeout=0.1)
        if self.cap and self.cap.isOpened():
            self.cap.release()
            self.cap = None

        self.log("Stream Perdida. Monitoramento Encerrado.")
        messagebox.showinfo("Stream Encerrada", "O sinal de vídeo foi perdido. Por favor, reinicie a sessão.")

    def update_ui_loop(self):
        try:
            if not self.frame_queue.empty():
                img_tk = self.frame_queue.get_nowait()
                self.canvas.create_image(0, 0, anchor=tk.NW, image=img_tk)
                self.canvas.image = img_tk

        except queue.Empty:
            pass
        finally:
            self.root.after(10, self.update_ui_loop)

    def _cleanup_video_thread(self):
        """Para a thread de vídeo de forma limpa e libera CAP."""
        self.running = False

        self.log("Encerrando transmissão...")

        if self.thread and self.thread.is_alive():
            self.thread.join(timeout=1.0)

        if self.cap and self.cap.isOpened():
            self.cap.release()
            self.cap = None

    # MÉTODO DE ENCERRAMENTO COM RELATÓRIO
    def stop_and_report(self, skip_confirm=False):
        if self.running:
            if not skip_confirm and not messagebox.askokcancel("Encerrar Transmissão",
                                                               "Gerar relatório, encerrar monitoramento e limpar dados para a próxima sessão?"):
                return

            self._cleanup_video_thread()
            self.session_end_ts = time.time()

            if self.session_start_ts:
                self.log("Gerando relatório...")
                self.generate_exact_report()

            self.db.clear_all()
            self.log("Dados de detecção limpos.")

        self.root.destroy()
        self.login_callback()

        # MÉTODO DEDICADO PARA SAIR E VOLTAR AO LOGIN SEM RELATÓRIO

    def exit_to_login(self):
        if messagebox.askyesno("Sair da Plataforma",
                               "Deseja realmente sair e voltar para a tela de Login? (A transmissão atual será encerrada sem relatório.)"):
            self._cleanup_video_thread()

            self.root.destroy()
            self.login_callback()

            # MÉTODO DE FECHAMENTO DA JANELA (X)

    def on_close(self):
        if self.running:
            response = messagebox.askyesnocancel("Sair da Plataforma",
                                                 "A transmissão está ativa. Deseja encerrá-la e gerar relatório antes de sair?\n\n- SIM: Encerra e gera relatório (Recomendado).\n- NÃO: Sai da plataforma, **SEM** relatório.\n- CANCELAR: Permanece na tela.")

            if response is True:
                self.stop_and_report()
                return
            elif response is False:
                self.exit_to_login()
                return
            else:
                return

        self.root.destroy()
        self.login_callback()

    def generate_exact_report(self):
        if not self.session_start_ts: self.session_start_ts = time.time()
        if not self.session_end_ts: self.session_end_ts = time.time()

        report_date_str = time.strftime('%Y-%m-%d %H:%M:%S')

        f_date = time.strftime('%Y-%m-%d', time.localtime(self.session_start_ts))
        f_start = time.strftime('%H-%M-%S', time.localtime(self.session_start_ts))
        f_end = time.strftime('%H-%M-%S', time.localtime(self.session_end_ts))
        filename = f"Relatório_{f_date}_{f_start}_{f_end}.pdf"

        duration_seconds = self.session_end_ts - self.session_start_ts
        data_rows = self.db.get_all()

        if not data_rows and duration_seconds < 10:
            self.log("Relatório não gerado: Nenhuma detecção registrada e sessão muito curta.")
            return

        try:
            doc = SimpleDocTemplate(filename, pagesize=letter, topMargin=1.5 * inch)
            styles = getSampleStyleSheet()
            elements = []

            title_style = styles['Title']
            title_style.fontName = 'Helvetica-Bold'
            title_style.fontSize = 16
            title_style.spaceAfter = 20

            elements.append(Paragraph("Relatório de Eventos de Detecção de Pessoas", title_style))

            normal_style = styles['Normal']
            normal_style.fontSize = 10
            normal_style.leading = 14

            elements.append(Paragraph(f"<b>Data de Geração do Relatório:</b> {report_date_str}", normal_style))
            elements.append(Paragraph(f"<b>Total de Eventos Registrados:</b> {len(data_rows)}", normal_style))
            elements.append(Spacer(1, 15))

            start_readable = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(self.session_start_ts))
            end_readable = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(self.session_end_ts))

            h2_style = styles['Heading2']
            h2_style.fontSize = 12
            h2_style.spaceAfter = 6

            elements.append(Paragraph(f"<b>Início da Transmissão:</b> {start_readable}", normal_style))
            elements.append(Paragraph(f"<b>Fim da Transmissão:</b> {end_readable}", normal_style))
            elements.append(Paragraph(f"<b>Duração da Sessão:</b> {duration_seconds:.2f} segundos", normal_style))
            elements.append(Spacer(1, 25))

            elements.append(Paragraph("Detalhes dos Eventos:", h2_style))
            elements.append(Spacer(1, 5))

            table_data = [['ID', 'Detalhe da Detecção', 'Horário']]
            for row in data_rows:
                t_str = time.strftime('%H:%M:%S', time.localtime(row[2]))
                table_data.append([str(row[0]), row[1], t_str])

            t = Table(table_data, colWidths=[60, 250, 120])
            t.setStyle(TableStyle([
                ('BACKGROUND', (0, 0), (-1, 0), colors.white),
                ('TEXTCOLOR', (0, 0), (-1, 0), colors.black),
                ('ALIGN', (0, 0), (-1, -1), 'LEFT'),
                ('FONTNAME', (0, 0), (-1, 0), 'Helvetica-Bold'),
                ('FONTSIZE', (0, 0), (-1, -1), 10),
                ('BOTTOMPADDING', (0, 0), (-1, 0), 8),
                ('LINEBELOW', (0, 0), (-1, 0), 1, colors.black),
                ('GRID', (0, 0), (-1, -1), 0.5, colors.lightgrey),
            ]))
            elements.append(t)

            doc.build(elements, canvasmaker=PDFHeaderFooter)

            messagebox.showinfo("Relatório", f"Relatório gerado com sucesso:\n{filename}")
            try:
                os.startfile(filename)
            except:
                pass

        except Exception as e:
            messagebox.showerror("Erro PDF", str(e))


# --- FUNÇÃO PRINCIPAL DE INÍCIO E LOOP (run_main_application) ---
def run_main_application(login_root):
    """
    Destrói a janela de login e inicia o monitoramento de segurança SkyHawkAuto.
    """
    login_root.destroy()

    main_root = tk.Tk()
    app = SkyHawkAuto(main_root, re_open_login)
    main_root.mainloop()


# FUNÇÃO REAJUSTADA
def re_open_login():
    """
    Reabre a tela de Login.
    A janela anterior já deve ter sido destruída.
    """
    app_root = tk.Tk()
    LoginWindow(app_root)
    app_root.mainloop()


# ----------------------------------------------------
# --- CLASSE DA JANELA DE LOGIN ---
# ----------------------------------------------------
class LoginWindow:
    def __init__(self, root):
        self.root = root
        self.root.title("SkyHawk - Autenticação")
        self.root.configure(bg=BG_COLOR)

        window_width = 400
        window_height = 500
        screen_width = self.root.winfo_screenwidth()
        screen_height = self.root.winfo_screenheight()
        center_x = int(screen_width / 2 - window_width / 2)
        center_y = int(screen_height / 2 - window_height / 2)
        self.root.geometry(f'{window_width}x{window_height}+{center_x}+{center_y}')

        self.root.resizable(False, False)

        self.load_images()
        self.setup_ui()

    def load_images(self):
        """Carrega e prepara os logotipos."""
        self.img_skyhawk = None
        self.img_inviolavel = None
        self.loaded_skyhawk = False
        self.loaded_inviolavel = False

        if os.path.exists(LOGO_ESQUERDA):
            try:
                img = Image.open(LOGO_ESQUERDA)
                img = img.resize((150, 80))
                self.img_skyhawk = ImageTk.PhotoImage(img)
                self.loaded_skyhawk = True
            except Exception:
                pass

        if os.path.exists(LOGO_DIREITA):
            try:
                img = Image.open(LOGO_DIREITA)
                img = img.resize((150, 80))
                self.img_inviolavel = ImageTk.PhotoImage(img)
                self.loaded_inviolavel = True
            except Exception:
                pass

    def setup_ui(self):
        """Cria os elementos da interface de login."""

        main_frame = tk.Frame(self.root, bg=BG_COLOR, padx=30, pady=30)
        main_frame.pack(expand=True)

        tk.Label(main_frame, text="Acesso Restrito", font=('Arial', 18, 'bold'),
                 bg=BG_COLOR, fg=FG_COLOR).pack(pady=(0, 20))

        # --- Área dos Logos ---
        logo_frame = tk.Frame(main_frame, bg=BG_COLOR)
        logo_frame.pack(pady=10)

        if self.loaded_skyhawk:
            tk.Label(logo_frame, image=self.img_skyhawk, bg=BG_COLOR).pack(side=tk.LEFT, padx=5)

        tk.Label(logo_frame, text="|", font=('Arial', 20), bg=BG_COLOR, fg='#777').pack(side=tk.LEFT, padx=10)

        if self.loaded_inviolavel:
            tk.Label(logo_frame, image=self.img_inviolavel, bg=BG_COLOR).pack(side=tk.LEFT, padx=5)

        tk.Label(main_frame, text="Monitoramento de Segurança", font=FONT_STYLE,
                 bg=BG_COLOR, fg='#BBB').pack(pady=(10, 30))

        # --- Campo Usuário ---
        tk.Label(main_frame, text="Usuário:", font=FONT_STYLE, bg=BG_COLOR, fg=FG_COLOR, anchor='w').pack(fill=tk.X,
                                                                                                          pady=(10, 2))
        self.user_entry = tk.Entry(main_frame, font=FONT_STYLE, width=30, bd=0,
                                   bg='#3E5060', fg=FG_COLOR, insertbackground=ACCENT_COLOR)
        self.user_entry.pack(ipady=5)
        self.user_entry.focus_set()

        # --- Campo Senha ---
        tk.Label(main_frame, text="Senha:", font=FONT_STYLE, bg=BG_COLOR, fg=FG_COLOR, anchor='w').pack(fill=tk.X,
                                                                                                        pady=(10, 2))
        self.pass_entry = tk.Entry(main_frame, font=FONT_STYLE, width=30, show='*', bd=0,
                                   bg='#3E5060', fg=FG_COLOR, insertbackground=ACCENT_COLOR)
        self.pass_entry.pack(ipady=5)

        self.pass_entry.bind('<Return>', lambda event=None: self.login())

        # --- Botão Login ---
        login_button = tk.Button(main_frame, text="Entrar", font=('Arial', 12, 'bold'),
                                 bg=ACCENT_COLOR, fg='white', relief=tk.FLAT,
                                 activebackground='#2980B9', activeforeground='white',
                                 command=self.login)
        login_button.pack(pady=30, ipadx=20, ipady=8, fill=tk.X)

    def login(self):
        """Verifica as credenciais e inicia o aplicativo principal."""
        username = self.user_entry.get()
        password = self.pass_entry.get()

        if username == USUARIO_PADRAO and password == SENHA_PADRAO:
            run_main_application(self.root)
        else:
            messagebox.showerror("Erro de Login", "Usuário ou senha incorretos.", parent=self.root)
            self.pass_entry.delete(0, tk.END)

        # ----------------------------------------------------


# --- INICIALIZAÇÃO ---
# ----------------------------------------------------
if __name__ == "__main__":
    try:
        pygame.mixer.init()
    except Exception:
        print("Aviso: Falha ao inicializar o Pygame Mixer. O alarme pode não funcionar.")

    app_root = tk.Tk()
    LoginWindow(app_root)
    app_root.mainloop()