import os
import sys
import time
import json
import fnmatch
import paramiko
from watchdog.observers import Observer
from watchdog.events import FileSystemEventHandler

WORKSPACE = r"e:\rescatado"
CONFIG_PATH = os.path.join(WORKSPACE, ".vscode", "sftp.json")

def load_config():
    with open(CONFIG_PATH, "r", encoding="utf-8") as f:
        return json.load(f)

cfg = load_config()
HOST = cfg.get("host", "laboptimus.com")
PORT = cfg.get("port", 22)
USER = cfg.get("username", "laboptimus")
PASS = cfg.get("password")
REMOTE_BASE = cfg.get("remotePath", "/home/laboptimus/public_html/")
IGNORE_PATTERNS = cfg.get("ignore", []) + [".git*", "*.zip", "*.pyc", "__pycache__*"]

def is_ignored(rel_path):
    norm = rel_path.replace("\\", "/")
    parts = norm.split("/")
    for pat in IGNORE_PATTERNS:
        pat_clean = pat.rstrip("/")
        if fnmatch.fnmatch(norm, pat_clean) or fnmatch.fnmatch(norm, pat):
            return True
        for p in parts:
            if fnmatch.fnmatch(p, pat_clean):
                return True
    return False

class SFTPSync:
    def __init__(self):
        self.ssh = None
        self.sftp = None
        self.connect()

    def connect(self):
        try:
            if self.sftp:
                try: self.sftp.close()
                except: pass
            if self.ssh:
                try: self.ssh.close()
                except: pass
            self.ssh = paramiko.SSHClient()
            self.ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
            self.ssh.connect(HOST, port=PORT, username=USER, password=PASS, timeout=15)
            self.sftp = self.ssh.open_sftp()
            print(f"[CONECTADO] SFTP listo con {HOST}:{PORT}")
        except Exception as e:
            print(f"[ERROR CONEXION] {e}")

    def ensure_remote_dir(self, remote_dir):
        dirs = []
        cur = remote_dir.replace("\\", "/")
        while cur and cur != "/":
            dirs.append(cur)
            cur = os.path.dirname(cur).replace("\\", "/")
        dirs.reverse()
        for d in dirs:
            try:
                self.sftp.stat(d)
            except IOError:
                try:
                    self.sftp.mkdir(d)
                except Exception:
                    pass

    def upload_file(self, local_path):
        rel = os.path.relpath(local_path, WORKSPACE)
        if is_ignored(rel):
            return
        remote_file = os.path.join(REMOTE_BASE, rel).replace("\\", "/")
        remote_dir = os.path.dirname(remote_file).replace("\\", "/")
        
        for attempt in range(2):
            try:
                self.ensure_remote_dir(remote_dir)
                self.sftp.put(local_path, remote_file)
                print(f"[SUBIDO] {rel} -> {remote_file}")
                return
            except Exception as e:
                print(f"[REINTENTO] Error subiendo {rel}: {e}")
                self.connect()

    def sync_all(self, target_subpath=""):
        scan_dir = os.path.join(WORKSPACE, target_subpath) if target_subpath else WORKSPACE
        print(f"[*] Iniciando subida completa desde: {scan_dir}")
        count = 0
        for root, dirs, files in os.walk(scan_dir):
            rel_root = os.path.relpath(root, WORKSPACE)
            if rel_root != "." and is_ignored(rel_root):
                dirs[:] = []
                continue
            for file in files:
                full_path = os.path.join(root, file)
                rel_path = os.path.relpath(full_path, WORKSPACE)
                if not is_ignored(rel_path):
                    self.upload_file(full_path)
                    count += 1
        print(f"[FIN] Se subieron {count} archivos.")

class AutoUploadHandler(FileSystemEventHandler):
    def __init__(self, syncer):
        self.syncer = syncer
        self.last_sync = {}

    def on_modified(self, event):
        if event.is_directory:
            return
        now = time.time()
        # Debounce 1 sec
        if now - self.last_sync.get(event.src_path, 0) < 1.0:
            return
        self.last_sync[event.src_path] = now
        self.syncer.upload_file(event.src_path)

    def on_created(self, event):
        if event.is_directory:
            return
        self.syncer.upload_file(event.src_path)

if __name__ == "__main__":
    mode = sys.argv[1] if len(sys.argv) > 1 else "watch"
    syncer = SFTPSync()
    if mode == "all":
        sub = sys.argv[2] if len(sys.argv) > 2 else ""
        syncer.sync_all(sub)
    elif mode == "watch":
        print(f"[*] Vigilando cambios en {WORKSPACE} para subida automática...")
        event_handler = AutoUploadHandler(syncer)
        observer = Observer()
        observer.schedule(event_handler, WORKSPACE, recursive=True)
        observer.start()
        try:
            while True:
                time.sleep(1)
        except KeyboardInterrupt:
            observer.stop()
        observer.join()

