#!/usr/bin/env python3

import os
import sys
import signal
import threading
import time
import json
import shutil
from http.server import HTTPServer, SimpleHTTPRequestHandler
import urllib.parse

sys.path.append(os.path.dirname(os.path.abspath(__file__)))

from config import Config
from mqtt_broker import MQTTBroker
from udp_broadcast import UDPBroadcast


class CustomHandler(SimpleHTTPRequestHandler):
    """Кастомный обработчик для веб-сервера"""
    
    def __init__(self, *args, sessions_dir=None, **kwargs):
        self.sessions_dir = sessions_dir
        super().__init__(*args, **kwargs)
    
    def do_GET(self):
        parsed = urllib.parse.urlparse(self.path)
        path = parsed.path
        
        if path == '/list':
            self._handle_list(parsed.query)
        elif path == '/getfile':
            self._handle_getfile(parsed.query)
        else:
            if path == '/':
                path = '/chart2_5.htm'
            
            file_path = os.path.join(os.path.dirname(__file__), path.lstrip('/'))
            if os.path.exists(file_path) and os.path.isfile(file_path):
                self._serve_file(file_path)
            else:
                self.send_error(404, "File not found")
    
    def do_DELETE(self):
        """Обработка DELETE запросов для удаления сессий"""
        parsed = urllib.parse.urlparse(self.path)
        path = parsed.path
        
        if path == '/delete_session':
            # Получаем параметры из query string
            params = urllib.parse.parse_qs(parsed.query)
            ip_dir = params.get('ip', [''])[0]
            session_time = params.get('time', [''])[0]
            
            if not ip_dir or not session_time:
                self.send_response(400)
                self.send_header('Content-Type', 'application/json')
                self.end_headers()
                self.wfile.write(json.dumps({'error': 'Missing ip or time'}).encode())
                return
            
            # Полный путь к директории IP
            ip_path = os.path.join(self.sessions_dir, ip_dir)
            
            if not os.path.exists(ip_path):
                self.send_response(404)
                self.send_header('Content-Type', 'application/json')
                self.end_headers()
                self.wfile.write(json.dumps({'error': 'Session not found'}).encode())
                return
            
            # Ищем и удаляем файлы, начинающиеся с session_time
            deleted = 0
            for filename in os.listdir(ip_path):
                if filename.startswith(session_time):
                    file_path = os.path.join(ip_path, filename)
                    try:
                        os.remove(file_path)
                        deleted += 1
                    except Exception as e:
                        print(f"Ошибка удаления {file_path}: {e}")
            
            # Если папка IP стала пустой, удаляем её
            if len(os.listdir(ip_path)) == 0:
                try:
                    os.rmdir(ip_path)
                except Exception:
                    pass
            
            if deleted > 0:
                self.send_response(200)
                self.send_header('Content-Type', 'application/json')
                self.end_headers()
                self.wfile.write(json.dumps({'success': True, 'deleted': deleted}).encode())
            else:
                self.send_response(404)
                self.send_header('Content-Type', 'application/json')
                self.end_headers()
                self.wfile.write(json.dumps({'error': 'No files found'}).encode())
        else:
            self.send_error(404, "Not found")
    
    def _handle_list(self, query):
        params = urllib.parse.parse_qs(query)
        list_path = params.get('list', ['/'])[0]
        
        if list_path == '/':
            real_path = self.sessions_dir
        else:
            real_path = os.path.join(self.sessions_dir, list_path.lstrip('/'))
        
        if not os.path.exists(real_path):
            self.send_response(500)
            self.send_header('Content-Type', 'application/json')
            self.end_headers()
            self.wfile.write(b'{"error":"Cannot open directory"}')
            return
        
        items = []
        try:
            for name in os.listdir(real_path):
                full_path = os.path.join(real_path, name)
                items.append({
                    'type': 'dir' if os.path.isdir(full_path) else 'file',
                    'name': name,
                    'size': os.path.getsize(full_path) if os.path.isfile(full_path) else 0
                })
        except Exception:
            pass
        
        self.send_response(200)
        self.send_header('Content-Type', 'application/json')
        self.end_headers()
        self.wfile.write(json.dumps(items).encode())
    
    def _handle_getfile(self, query):
        params = urllib.parse.parse_qs(query)
        file_path = params.get('path', [''])[0]
        
        if not file_path:
            self.send_error(400, "BAD ARGS")
            return
        
        if file_path.startswith('/'):
            file_path = file_path[1:]
        
        full_path = os.path.join(self.sessions_dir, file_path)
        
        if not os.path.exists(full_path) or not os.path.isfile(full_path):
            self.send_error(404, "File not found")
            return
        
        self._serve_file(full_path)
    
    def _serve_file(self, file_path):
        ext = os.path.splitext(file_path)[1].lower()
        mime_types = {
            '.htm': 'text/html', '.html': 'text/html',
            '.css': 'text/css', '.js': 'application/javascript',
            '.json': 'application/json', '.png': 'image/png',
            '.jpg': 'image/jpeg', '.jpeg': 'image/jpeg',
            '.gif': 'image/gif', '.ico': 'image/x-icon',
            '.txt': 'text/plain'
        }
        content_type = mime_types.get(ext, 'application/octet-stream')
        
        try:
            with open(file_path, 'rb') as f:
                content = f.read()
            
            self.send_response(200)
            self.send_header('Content-Type', content_type)
            self.send_header('Content-Length', str(len(content)))
            self.end_headers()
            self.wfile.write(content)
        except Exception:
            self.send_error(500, "Error reading file")


class LoggerPC:
    def __init__(self):
        self.config = Config()
        self.running = False
        self.threads = []
        self.http_server = None
        self._init_components()
        signal.signal(signal.SIGINT, self._signal_handler)
        signal.signal(signal.SIGTERM, self._signal_handler)

    def _init_components(self):
        print("=" * 50)
        print("Logger PC v1.4")
        print("=" * 50)

        os.makedirs(self.config.SESSIONS_DIR, exist_ok=True)

        self.mqtt_broker = MQTTBroker(
            host=self.config.MQTT_HOST,
            port=self.config.MQTT_PORT,
            sessions_dir=self.config.SESSIONS_DIR,
            session_timeout=self.config.SESSION_TIMEOUT,
            max_points_per_session=self.config.MAX_POINTS_PER_SESSION
        )

        self.udp_broadcast = UDPBroadcast(
            port=self.config.UDP_PORT,
            interval=self.config.UDP_INTERVAL,
            device_name=self.config.DEVICE_NAME,
            mask=self.config.MASK
        )

        print("Компоненты инициализированы")

    def start(self):
        print("Запуск компонентов...")
        self.running = True

        http_thread = threading.Thread(target=self._run_http_server, daemon=True)
        http_thread.start()
        self.threads.append(http_thread)

        mqtt_thread = threading.Thread(target=self._run_mqtt, daemon=True)
        mqtt_thread.start()
        self.threads.append(mqtt_thread)

        udp_thread = threading.Thread(target=self._run_udp, daemon=True)
        udp_thread.start()
        self.threads.append(udp_thread)

        self._main_loop()

    def _run_http_server(self):
        try:
            handler = lambda *args, **kwargs: CustomHandler(
                *args, sessions_dir=self.config.SESSIONS_DIR, **kwargs
            )
            self.http_server = HTTPServer(('0.0.0.0', 8080), handler)
            print(f"HTTP сервер запущен на http://localhost:8080")
            print("Откройте в браузере: http://localhost:8080/chart2_5.htm")
            self.http_server.serve_forever()
        except Exception as e:
            print(f"Ошибка HTTP сервера: {e}")

    def _run_mqtt(self):
        try:
            self.mqtt_broker.start()
        except Exception as e:
            print(f"Ошибка MQTT брокера: {e}")

    def _run_udp(self):
        try:
            self.udp_broadcast.start()
        except Exception as e:
            print(f"Ошибка UDP broadcast: {e}")

    def _main_loop(self):
        print("\n" + "=" * 50)
        print("Logger PC запущен")
        print(f"MQTT брокер: {self.config.MQTT_HOST}:{self.config.MQTT_PORT}")
        print(f"UDP broadcast порт: {self.config.UDP_PORT}")
        print(f"Директория сессий: {self.config.SESSIONS_DIR}")
        print(f"Максимум точек на сессию: {self.config.MAX_POINTS_PER_SESSION}")
        print(f"Веб-интерфейс: http://localhost:8080/chart2_5.htm")
        print("=" * 50)
        print("\nНажмите Ctrl+C для остановки")

        last_cleanup = time.time()

        while self.running:
            try:
                if time.time() - last_cleanup >= 30:
                    self.mqtt_broker.cleanup_sessions()
                    last_cleanup = time.time()
                time.sleep(0.1)
            except KeyboardInterrupt:
                break
            except Exception:
                time.sleep(1)

    def stop(self):
        print("\nОстановка компонентов...")
        self.running = False

        if self.http_server:
            self.http_server.shutdown()
        
        if hasattr(self, 'mqtt_broker'):
            self.mqtt_broker.stop()
        if hasattr(self, 'udp_broadcast'):
            self.udp_broadcast.stop()

        for thread in self.threads:
            thread.join(timeout=2)

        print("Logger PC остановлен")

    def _signal_handler(self, signum, frame):
        self.stop()
        sys.exit(0)


def main():
    logger = LoggerPC()
    try:
        logger.start()
    except KeyboardInterrupt:
        logger.stop()
    except Exception as e:
        print(f"Критическая ошибка: {e}")
        logger.stop()
        sys.exit(1)


if __name__ == "__main__":
    main()