"""
MainWindow - главное окно приложения на tkinter
"""

import tkinter as tk
from tkinter import ttk, messagebox, filedialog, simpledialog
from pathlib import Path
from threading import Thread
import subprocess
import platform
from datetime import datetime

from services.config_service import ConfigService
from services.session_service import SessionService
from services.watch_service import WatchService
from services.file_service import FileService


class MainWindow:
    """Главное окно приложения"""

    def __init__(self, root):
        self.root = root
        self.root.title("Astro Session Watcher v0.4.0")
        self.root.geometry("800x550")
        self.root.minsize(700, 500)
        self.center_window()

        # Сервисы
        self.config_service = ConfigService()
        self.session_service = SessionService()
        self.watch_service = WatchService()

        # Переменные состояния
        self.running = False
        self.file_count = 0
        self.current_target = ""
        self.current_session_folder = ""
        self._blink_active = False

        # Стили
        self._setup_styles()

        # Создаём интерфейс
        self._create_menu_bar()
        self._create_main_content()
        self._load_saved_settings()
        self._setup_hotkeys()

        # Обновление счётчика
        self._update_file_count_display()

        # Обработчик закрытия
        self.root.protocol("WM_DELETE_WINDOW", self._on_closing)

    def center_window(self):
        self.root.update_idletasks()
        x = (self.root.winfo_screenwidth() // 2) - (self.root.winfo_width() // 2)
        y = (self.root.winfo_screenheight() // 2) - (self.root.winfo_height() // 2)
        self.root.geometry(f'+{x}+{y}')

    def _setup_styles(self):
        style = ttk.Style()
        style.theme_use('clam')

        # Тёмная тема
        style.configure('.', background='#1e1e1e', foreground='#e0e0e0')
        style.configure('TLabel', background='#1e1e1e', foreground='#e0e0e0')
        style.configure('TFrame', background='#1e1e1e')
        style.configure('TLabelframe', background='#1e1e1e', foreground='#e0e0e0')
        style.configure('TLabelframe.Label', background='#1e1e1e', foreground='#e0e0e0')

        # Кнопки
        style.configure('TButton', background='#3c3c3c', foreground='#e0e0e0', borderwidth=1)
        style.map('TButton',
                  background=[('active', '#4c4c4c')],
                  foreground=[('active', '#ffffff')])

        # Поля ввода
        style.configure('TEntry', fieldbackground='#3c3c3c', foreground='#e0e0e0')
        style.configure('TCombobox', fieldbackground='#3c3c3c', foreground='#e0e0e0')

        # Специальные кнопки
        style.configure('Green.TButton', background='#4CAF50', foreground='white')
        style.map('Green.TButton', background=[('active', '#45a049')])

        style.configure('Red.TButton', background='#f44336', foreground='black')
        style.map('Red.TButton', background=[('active', '#d32f2f')])

        self.root.configure(bg='#1e1e1e')

    def _create_menu_bar(self):
        menubar = tk.Menu(self.root)
        self.root.config(menu=menubar)

        # File menu
        file_menu = tk.Menu(menubar, tearoff=0)
        menubar.add_cascade(label="File", menu=file_menu)
        file_menu.add_command(label="Select Folder...", command=self.select_folder, accelerator="Ctrl+O")
        file_menu.add_separator()
        file_menu.add_command(label="Equipment...", command=self.open_equipment_dialog, accelerator="Ctrl+E")
        file_menu.add_command(label="Celestial Bodies...", command=self.open_celestial_dialog, accelerator="Ctrl+B")
        file_menu.add_separator()
        file_menu.add_command(label="Exit", command=self._on_closing, accelerator="Ctrl+Q")

        # Session menu
        session_menu = tk.Menu(menubar, tearoff=0)
        menubar.add_cascade(label="Session", menu=session_menu)
        session_menu.add_command(label="Start Tracking", command=self.start, accelerator="Ctrl+S")
        session_menu.add_command(label="Stop", command=self.stop, accelerator="Ctrl+X")
        session_menu.add_separator()
        session_menu.add_command(label="Open Session Folder", command=self.open_session_folder, accelerator="Ctrl+F")
        session_menu.add_separator()
        session_menu.add_command(label="New Target...", command=self.set_new_object, accelerator="Ctrl+Shift+N")
        session_menu.add_separator()
        session_menu.add_command(label="Calibration Frames...", command=self.open_calibration_dialog, accelerator="Ctrl+K")

        # Help menu
        help_menu = tk.Menu(menubar, tearoff=0)
        menubar.add_cascade(label="Help", menu=help_menu)
        help_menu.add_command(label="Instructions", command=self.show_instructions, accelerator="F2")
        help_menu.add_separator()
        help_menu.add_command(label="About", command=self.show_info, accelerator="F1")

    def _create_main_content(self):
        # Main frame
        main_frame = ttk.Frame(self.root, padding="20")
        main_frame.pack(fill="both", expand=True)

        # Grid layout
        main_frame.grid_columnconfigure(0, weight=0, minsize=100)
        main_frame.grid_columnconfigure(1, weight=1)

        # Row 0: Folder
        ttk.Label(main_frame, text="Folder:", font=('Segoe UI', 10, 'bold')).grid(row=0, column=0, sticky='w', pady=5)
        folder_frame = ttk.Frame(main_frame)
        folder_frame.grid(row=0, column=1, sticky='ew', pady=5)
        folder_frame.grid_columnconfigure(0, weight=1)

        self.folder_entry = ttk.Entry(folder_frame)
        self.folder_entry.grid(row=0, column=0, sticky='ew', padx=(0, 10))
        self.folder_entry.insert(0, "Select watch folder...")
        self.folder_entry.bind('<FocusIn>', lambda e: self._clear_placeholder(self.folder_entry, "Select watch folder..."))
        self.folder_entry.bind('<FocusOut>', lambda e: self._restore_placeholder(self.folder_entry, "Select watch folder..."))

        self.browse_btn = ttk.Button(folder_frame, text="Browse...", width=10, command=self.select_folder)
        self.browse_btn.grid(row=0, column=1)

        # Row 1: Equipment
        ttk.Label(main_frame, text="Equipment:", font=('Segoe UI', 10, 'bold')).grid(row=1, column=0, sticky='w', pady=5)
        equipment_frame = ttk.Frame(main_frame)
        equipment_frame.grid(row=1, column=1, sticky='ew', pady=5)
        equipment_frame.grid_columnconfigure(0, weight=1)
        equipment_frame.grid_columnconfigure(1, weight=1)

        self.camera_combo = ttk.Combobox(equipment_frame, values=[])
        self.camera_combo.grid(row=0, column=0, sticky='ew', padx=(0, 10))
        self.camera_combo.set("Select or enter camera...")
        self.camera_combo.bind('<FocusIn>', lambda e: self._clear_combo(self.camera_combo, "Select or enter camera..."))
        self.camera_combo.bind('<FocusOut>', lambda e: self._restore_combo(self.camera_combo, "Select or enter camera..."))

        self.lens_combo = ttk.Combobox(equipment_frame, values=[])
        self.lens_combo.grid(row=0, column=1, sticky='ew')
        self.lens_combo.set("Select or enter lens/telescope...")
        self.lens_combo.bind('<FocusIn>', lambda e: self._clear_combo(self.lens_combo, "Select or enter lens/telescope..."))
        self.lens_combo.bind('<FocusOut>', lambda e: self._restore_combo(self.lens_combo, "Select or enter lens/telescope..."))

        # Row 2: Target
        ttk.Label(main_frame, text="Target:", font=('Segoe UI', 10, 'bold')).grid(row=2, column=0, sticky='w', pady=5)
        target_frame = ttk.Frame(main_frame)
        target_frame.grid(row=2, column=1, sticky='ew', pady=5)
        target_frame.grid_columnconfigure(0, weight=1)

        self.target_combo = ttk.Combobox(target_frame, values=[])
        self.target_combo.grid(row=0, column=0, sticky='ew', padx=(0, 10))
        self.target_combo.set("Enter target name...")
        self.target_combo.bind('<FocusIn>', lambda e: self._clear_combo(self.target_combo, "Enter target name..."))
        self.target_combo.bind('<FocusOut>', lambda e: self._restore_combo(self.target_combo, "Enter target name..."))

        self.new_target_btn = ttk.Button(target_frame, text="New Target", width=12, command=self.set_new_object)
        self.new_target_btn.grid(row=0, column=1)
        self.new_target_btn.configure(state='disabled')

        # Row 3: Statistics
        ttk.Label(main_frame, text="Statistics:", font=('Segoe UI', 10, 'bold')).grid(row=3, column=0, sticky='w', pady=5)
        self.stats_label = ttk.Label(main_frame, text="Files received: 0", font=('Segoe UI', 11))
        self.stats_label.grid(row=3, column=1, sticky='w', pady=5)

        # Row 4: Status
        ttk.Label(main_frame, text="Status:", font=('Segoe UI', 10, 'bold')).grid(row=4, column=0, sticky='w', pady=5)
        self.status_label = ttk.Label(main_frame, text="IDLE", font=('Segoe UI', 12, 'bold'), foreground='#666666')
        self.status_label.grid(row=4, column=1, sticky='w', pady=5)

        # Separator
        separator = ttk.Separator(main_frame, orient='horizontal')
        separator.grid(row=5, column=0, columnspan=2, sticky='ew', pady=15)

        # Buttons
        buttons_frame = ttk.Frame(main_frame)
        buttons_frame.grid(row=6, column=0, columnspan=2, pady=10)

        self.start_btn = ttk.Button(buttons_frame, text="▶ Start Tracking", width=18, command=self.start, style='Green.TButton')
        self.start_btn.pack(side='left', padx=10)

        self.stop_btn = ttk.Button(buttons_frame, text="■ Stop", width=12, command=self.stop, style='Red.TButton')
        self.stop_btn.pack(side='left', padx=10)
        self.stop_btn.configure(state='disabled')

        # Footer
        footer_frame = ttk.Frame(self.root)
        footer_frame.pack(side='bottom', fill='x', padx=20, pady=(0, 10))

        ttk.Label(footer_frame, text="v0.4.0-alpha", foreground='#666666').pack(side='left')
        ttk.Label(footer_frame, text="Made by Vic Sergeev 2026", foreground='#666666').pack(side='right')

    def _clear_placeholder(self, entry, placeholder):
        if entry.get() == placeholder:
            entry.delete(0, 'end')

    def _restore_placeholder(self, entry, placeholder):
        if entry.get() == '':
            entry.insert(0, placeholder)

    def _clear_combo(self, combo, placeholder):
        if combo.get() == placeholder:
            combo.set('')

    def _restore_combo(self, combo, placeholder):
        if combo.get() == '':
            combo.set(placeholder)

    def _load_saved_settings(self):
        cameras = self.config_service.get_cameras()
        lenses = self.config_service.get_lenses()
        telescopes = self.config_service.get_telescopes()
        celestial_bodies = self.config_service.get_celestial_bodies()

        all_optics = []
        for lens in lenses:
            all_optics.append(lens)
        for telescope in telescopes:
            all_optics.append(telescope)

        if cameras:
            self.camera_combo['values'] = cameras
            last_camera = self.config_service.get_last_camera()
            if last_camera and last_camera in cameras:
                self.camera_combo.set(last_camera)

        if all_optics:
            self.lens_combo['values'] = all_optics
            last_lens = self.config_service.get_last_lens()
            if last_lens and last_lens in all_optics:
                self.lens_combo.set(last_lens)

        if celestial_bodies:
            self.target_combo['values'] = celestial_bodies

        last_folder = self.config_service.get_last_watch_folder()
        if last_folder:
            self.folder_entry.delete(0, 'end')
            self.folder_entry.insert(0, last_folder)

    def _setup_hotkeys(self):
        def on_key(event):
            if event.state & 0x4:  # Ctrl
                if event.keysym == 'o':
                    self.select_folder()
                elif event.keysym == 'e':
                    self.open_equipment_dialog()
                elif event.keysym == 'b':
                    self.open_celestial_dialog()
                elif event.keysym == 's':
                    self.start()
                elif event.keysym == 'x':
                    self.stop()
                elif event.keysym == 'f':
                    self.open_session_folder()
                elif event.keysym == 'k':
                    self.open_calibration_dialog()
            elif event.state & 0x6:  # Ctrl+Shift
                if event.keysym == 'N':
                    self.set_new_object()
            elif event.keysym == 'F1':
                self.show_info()
            elif event.keysym == 'F2':
                self.show_instructions()

        self.root.bind_all('<Key>', on_key)

    def _set_running_state(self, state):
        self.running = state

        if state:
            self.start_btn.configure(state='disabled')
            self.stop_btn.configure(state='normal')
            self.new_target_btn.configure(state='normal')
            self.status_label.configure(text="● ON AIR", foreground='#ff0000')
            self._start_blinking()
        else:
            self.start_btn.configure(state='normal')
            self.stop_btn.configure(state='disabled')
            self.new_target_btn.configure(state='disabled')
            self.status_label.configure(text="IDLE", foreground='#666666')
            self._stop_blinking()

    def _start_blinking(self):
        self._blink_active = True
        self._do_blink()

    def _do_blink(self):
        if not self._blink_active or not self.running:
            return
        current = self.status_label.cget('foreground')
        new_color = '#ffffff' if current == '#ff0000' else '#ff0000'
        self.status_label.configure(foreground=new_color)
        self.root.after(500, self._do_blink)

    def _stop_blinking(self):
        self._blink_active = False
        self.status_label.configure(foreground='#666666')

    def _update_file_count_display(self):
        if self.running and self.session_service.get_current_object():
            current_obj = self.session_service.get_current_object()
            self.file_count = current_obj.photo_count
        self.stats_label.configure(text=f"Files received: {self.file_count}")
        self.root.after(1000, self._update_file_count_display)

    def _on_file_received(self, file_path: Path):
        if self.session_service.handle_file(file_path):
            self.file_count += 1
            self.stats_label.configure(text=f"Files received: {self.file_count}")
            print(f"File processed: {file_path.name}")

    def select_folder(self):
        folder = filedialog.askdirectory(title="Select watch folder")
        if folder:
            self.folder_entry.delete(0, 'end')
            self.folder_entry.insert(0, folder)
            self.config_service.set_last_watch_folder(folder)

    def start(self):
        watch_folder = self.folder_entry.get()
        target_name = self.target_combo.get()
        camera = self.camera_combo.get()
        lens = self.lens_combo.get()

        # Skip placeholders
        if watch_folder == "Select watch folder...":
            watch_folder = ""
        if target_name == "Enter target name...":
            target_name = ""
        if camera == "Select or enter camera...":
            camera = ""
        if lens == "Select or enter lens/telescope...":
            lens = ""

        if not watch_folder:
            messagebox.showerror("Error", "Please select a folder to watch!", parent=self.root)
            return

        if not target_name:
            messagebox.showerror("Error", "Please enter a target name!", parent=self.root)
            return

        celestial_bodies = self.config_service.get_celestial_bodies()
        if target_name not in celestial_bodies:
            reply = messagebox.askyesno("New Target",
                f"Target '{target_name}' not found in list.\nAdd it to the list?",
                parent=self.root)
            if reply:
                self.config_service.add_celestial_body(target_name)
                self.target_combo['values'] = self.config_service.get_celestial_bodies()
                self.target_combo.set(target_name)
            else:
                return

        if not camera or not lens:
            reply = messagebox.askyesno("Warning", "Camera or lens not selected. Continue?",
                parent=self.root)
            if not reply:
                return

        try:
            watch_path = Path(watch_folder)
            FileService.clear_watch_folder(watch_path)

            camera_val = camera if camera else "Unknown"
            lens_val = lens if lens else "Unknown"

            self.session_service.start_session(watch_path, target_name, camera_val, lens_val)
            self.current_target = target_name
            self.current_session_folder = str(self.session_service.get_current_session().session_folder)

            self.config_service.set_last_camera(camera_val)
            self.config_service.set_last_lens(lens_val)

            success = self.watch_service.start(watch_path, self._on_file_received)
            if not success:
                messagebox.showerror("Error", "Failed to start watching folder!", parent=self.root)
                return

            self._set_running_state(True)

        except Exception as e:
            messagebox.showerror("Error", f"Failed to start session: {e}", parent=self.root)
            import traceback
            traceback.print_exc()

    def stop(self):
        if not self.running:
            return

        try:
            watch_folder = Path(self.folder_entry.get())
            self.watch_service.move_all_existing_files(watch_folder, self._on_file_received)
            self.watch_service.stop()
            session = self.session_service.finish_session()
            self._set_running_state(False)
            self._show_session_end_dialog(session)
        except Exception as e:
            messagebox.showerror("Error", f"Error stopping session: {e}", parent=self.root)

    def set_new_object(self):
        if not self.running:
            messagebox.showerror("Error", "Session is not active!", parent=self.root)
            return

        watch_folder = Path(self.folder_entry.get())
        self.watch_service.move_all_existing_files(watch_folder, self._on_file_received)

        dialog = tk.Toplevel(self.root)
        dialog.title("New Target")
        dialog.geometry("400x150")
        dialog.transient(self.root)
        dialog.grab_set()

        ttk.Label(dialog, text="Enter new target name:", font=('Segoe UI', 11)).pack(pady=20)

        entry = ttk.Entry(dialog, width=40)
        entry.pack(pady=10)
        entry.focus()

        def confirm():
            new_target = entry.get().strip()
            if new_target:
                dialog.destroy()
                self._create_new_target(new_target)
            else:
                messagebox.showwarning("Warning", "Please enter a target name!", parent=dialog)

        ttk.Button(dialog, text="OK", command=confirm).pack(pady=10)
        dialog.bind('<Return>', lambda e: confirm())

        self.root.wait_window(dialog)

    def _create_new_target(self, new_name):
        celestial_bodies = self.config_service.get_celestial_bodies()
        if new_name not in celestial_bodies:
            reply = messagebox.askyesno("New Target",
                f"Target '{new_name}' not found in list.\nAdd it to the list?",
                parent=self.root)
            if reply:
                self.config_service.add_celestial_body(new_name)
                self.target_combo['values'] = self.config_service.get_celestial_bodies()
            else:
                return

        self.session_service.create_new_object(new_name)
        self.target_combo.set(new_name)
        self.file_count = 0
        self.stats_label.configure(text="Files received: 0")

    def open_equipment_dialog(self):
        from ui.dialogs.equipment_dialog import EquipmentDialog
        dialog = EquipmentDialog(self.root, self.config_service)
        self.root.wait_window(dialog)

        # Refresh comboboxes
        cameras = self.config_service.get_cameras()
        lenses = self.config_service.get_lenses()
        telescopes = self.config_service.get_telescopes()

        all_optics = lenses + telescopes

        self.camera_combo['values'] = cameras
        self.lens_combo['values'] = all_optics

    def open_celestial_dialog(self):
        from ui.dialogs.celestial_dialog import CelestialDialog
        dialog = CelestialDialog(self.root, self.config_service)
        self.root.wait_window(dialog)

        celestial_bodies = self.config_service.get_celestial_bodies()
        self.target_combo['values'] = celestial_bodies

    def open_calibration_dialog(self):
        from ui.dialogs.calibration_dialog import CalibrationDialog
        dialog = CalibrationDialog(self.root, self.config_service)
        self.root.wait_window(dialog)

    def open_session_folder(self):
        if self.running and self.current_session_folder:
            try:
                if platform.system() == "Windows":
                    subprocess.Popen(['explorer', self.current_session_folder])
                elif platform.system() == "Darwin":
                    subprocess.Popen(['open', self.current_session_folder])
                else:
                    subprocess.Popen(['xdg-open', self.current_session_folder])
            except Exception as e:
                messagebox.showerror("Error", f"Failed to open folder: {e}", parent=self.root)
        else:
            messagebox.showinfo("Info", "No active session", parent=self.root)

    def show_instructions(self):
        from ui.dialogs.instructions_dialog import InstructionsDialog
        InstructionsDialog(self.root)

    def show_info(self):
        messagebox.showinfo("About",
            "Astro Session Watcher v0.4.0\n\n"
            "Application for astrophotographers\n\n"
            "Features:\n"
            "• Automatic file tracking\n"
            "• Sorting by targets\n"
            "• Session logging\n"
            "• Equipment management\n\n"
            "Made by Vic Sergeev\n2026",
            parent=self.root)

    def _show_session_end_dialog(self, session):
        current_object = session.get_current_object()
        object_name = current_object.name if current_object else "Unknown"
        photo_count = current_object.photo_count if current_object else 0
        session_folder = session.session_folder

        dialog = tk.Toplevel(self.root)
        dialog.title("Session Completed")
        dialog.geometry("500x250")
        dialog.transient(self.root)
        dialog.grab_set()

        ttk.Label(dialog, text="✅ Session finished!", font=('Segoe UI', 14, 'bold')).pack(pady=15)
        ttk.Label(dialog, text=f"Target: {object_name}").pack()
        ttk.Label(dialog, text=f"Files received: {photo_count}").pack()
        ttk.Label(dialog, text=f"Saved to: {session_folder}", wraplength=450).pack(pady=10)

        def open_folder():
            if session_folder and session_folder.exists():
                try:
                    if platform.system() == "Windows":
                        subprocess.Popen(['explorer', str(session_folder)])
                    elif platform.system() == "Darwin":
                        subprocess.Popen(['open', str(session_folder)])
                    else:
                        subprocess.Popen(['xdg-open', str(session_folder)])
                except Exception as e:
                    messagebox.showerror("Error", f"Failed to open folder: {e}", parent=dialog)
            dialog.destroy()

        def close():
            dialog.destroy()

        btn_frame = ttk.Frame(dialog)
        btn_frame.pack(pady=20)
        ttk.Button(btn_frame, text="Open Folder", command=open_folder).pack(side='left', padx=10)
        ttk.Button(btn_frame, text="Close", command=close).pack(side='left', padx=10)

    def _on_closing(self):
        if self.running:
            reply = messagebox.askyesno("Exit", "Session is active. Stop session and exit?",
                parent=self.root)
            if reply:
                self.stop()
                self.root.destroy()
        else:
            self.root.destroy()