import os
import ftplib
from pathlib import Path
from dotenv import load_dotenv

load_dotenv()

class FTPUtils:
    _EXTENSIONS_ALLOWED = {
        '.pdf', '.doc', '.docx', '.jpg', '.jpeg', '.png', '.xlsx', '.xls', '.txt'
    }

    _URL_BASE   = os.getenv("BASE_URL", "https://file.sycelephant.com").rstrip("/")
    _FTP_HOST   = os.getenv("FTP_HOST")
    _FTP_USER   = os.getenv("FTP_USER")
    _FTP_PASS   = os.getenv("FTP_PASS")
    _FTP_PORT   = int(os.getenv("FTP_PORT", "21"))
    _USE_TLS    = str(os.getenv("USE_TLS", "true")).lower() in ("1","true","yes")
    _FTP_DOMAIN = os.getenv("FTP_DOMAIN", "").strip()

    # Bases posibles en Hostinger
    _BASES = []
    _BASES.append("/public_html/file")
    if _FTP_DOMAIN:
        _BASES.append(f"/domains/{_FTP_DOMAIN}/public_html/file")


    @classmethod
    def _rel_from_input(cls, ruta: str) -> str:
        """Devuelve la ruta relativa bajo 'file', p. ej. 'Formatos/mi.pdf'."""
        if not ruta:
            raise ValueError("Ruta vacía")
        s = ruta.strip().replace("\\", "/")
        # URL pública
        if s.startswith(cls._URL_BASE):
            return s[len(cls._URL_BASE):].lstrip("/")
        # Ruta FTP absoluta conocida
        for base in cls._BASES:
            if s.startswith(base):
                return s[len(base):].lstrip("/")
        # Si viene con slash inicial, quítalo
        return s.lstrip("/")


    @classmethod
    def _connect(cls):
        if not cls._FTP_HOST or not cls._FTP_USER or not cls._FTP_PASS:
            raise RuntimeError("Faltan credenciales FTP (FTP_HOST/FTP_USER/FTP_PASS).")
        conn = ftplib.FTP_TLS() if cls._USE_TLS else ftplib.FTP()
        conn.connect(cls._FTP_HOST, cls._FTP_PORT, timeout=30)
        conn.login(cls._FTP_USER, cls._FTP_PASS)
        if isinstance(conn, ftplib.FTP_TLS):
            conn.prot_p()  # protege canal de datos
        conn.set_pasv(True)
        return conn


    @classmethod
    def file_exists(cls, ruta: str) -> bool:
        """
        Verifica si existe el archivo. Acepta:
          - URL pública: https://file.sycelephant.com/Formatos/mi.pdf
          - FTP absoluto: /public_html/file/Formatos/mi.pdf  (o /domains/.../public_html/file/...)
          - Relativa:     Formatos/mi.pdf  o  /Formatos/mi.pdf
        """
        rel = cls._rel_from_input(ruta)
        name = Path(rel).name
        dir_rel = str(Path(rel).parent).replace("\\", "/")
        try:
            conn = cls._connect()
            # Probar cada base conocida
            for base in cls._BASES:
                try:
                    conn.cwd(f"{base}/{dir_rel}" if dir_rel else base)
                    # 1) SIZE si está disponible
                    try:
                        conn.size(name)
                        conn.quit()
                        return True
                    except ftplib.error_perm:
                        # 550 o no soportado: probemos con NLST
                        files = conn.nlst()
                        if name in files:
                            conn.quit()
                            return True
                except ftplib.error_perm:
                    # No existe ese directorio en esta base, intentamos la siguiente base
                    continue
            conn.quit()
            return False
        except Exception:
            return False


    @classmethod
    def download_file(cls, remote_path: str, local_path: str) -> dict:
        """
        Descarga un archivo. 'remote_path' puede ser URL pública, FTP absoluto o relativo.
        """
        try:
            rel = cls._rel_from_input(remote_path)
            ext = Path(rel).suffix.lower()
            if ext and ext not in cls._EXTENSIONS_ALLOWED:
                return {"success": False, "message": f"Extensión no permitida: {ext}"}

            name = Path(rel).name
            dir_rel = str(Path(rel).parent).replace("\\", "/")

            dest_dir = os.path.dirname(local_path)
            if dest_dir:
                os.makedirs(dest_dir, exist_ok=True)

            conn = cls._connect()
            # CWD a la base válida
            ok = False
            for base in cls._BASES:
                try:
                    conn.cwd(f"{base}/{dir_rel}" if dir_rel else base)
                    ok = True
                    break
                except ftplib.error_perm:
                    continue
            if not ok:
                conn.quit()
                return {"success": False, "message": "Directorio remoto no encontrado en ninguna base."}

            with open(local_path, "wb") as f:
                conn.retrbinary(f"RETR {name}", f.write)
            conn.quit()

            public_url = f"{cls._URL_BASE}/{rel}"
            return {
                "success": True,
                "message": f"Archivo descargado en {local_path}",
                "local_path": local_path,
                "remote_relative": rel,
                "public_url": public_url
            }
        except Exception as e:
            return {"success": False, "message": f"Error al descargar: {e}"}