import os
import sys
from datetime import datetime

try:
    from pyftpdlib.authorizers import DummyAuthorizer
    from pyftpdlib.handlers import FTPHandler
    from pyftpdlib.servers import ThreadedFTPServer
except ImportError:
    print("Dependência ausente. Instale com:\n    pip install pyftpdlib")
    sys.exit(1)

# ============================ CONFIGURAÇÃO ============================
FTP_HOST = "0.0.0.0"
FTP_PORT = 2121                                 # porta do servidor FTP
FTP_ROOT = os.path.abspath(".")                 # diretório raiz servido (equivale ao cwd do webserver)

# --- Usuários (usuário/senha) ---
# Adicione quantos quiser chamando authorizer.add_user(...) em setup_authorizer().
FTP_USERS = [
    # (usuario,   senha,              pasta,     permissões)
    ("jrussi@gmail.com",     "jkiller77", FTP_ROOT,  "elradfmwMT"),
]

ALLOW_ANONYMOUS = False                         # True = permite login anônimo (somente leitura)
ANON_PERM = "elr"                               # permissões do anônimo: listar + baixar, sem escrever

PASSIVE_PORTS = range(60000, 60050)             # faixa de portas passivas (necessário atrás de NAT/firewall)
MAX_CONNECTIONS = 256
MAX_CONNECTIONS_PER_IP = 10
BANNER = "Servidor FTP pronto."
# ========================================================================

# Legenda de permissões (pyftpdlib):
#   e = entrar em diretórios (CWD)      l = listar (LIST/NLST/MLSD)     r = baixar (RETR)
#   a = anexar dados (APPE)             d = deletar (DELE/RMD)          f = renomear (RNFR/RNTO)
#   m = criar diretório (MKD)           w = enviar arquivo (STOR/STOU)
#   M = alterar modo do arquivo (CHMOD) T = alterar data de modificação (MFMT)


def format_file_size(size_bytes):
    if size_bytes < 1024: return f"{size_bytes} B"
    elif size_bytes < 1024**2: return f"{size_bytes/1024:.1f} KB"
    elif size_bytes < 1024**3: return f"{size_bytes/1024**2:.1f} MB"
    else: return f"{size_bytes/1024**3:.1f} GB"


def log(tag, msg, ok=True):
    ts = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
    status = "OK  " if ok else "ERRO"
    print(f"[{ts}] {status}  {tag:<8}  {msg}")


class MyFTPHandler(FTPHandler):
    """Handler customizado — só adiciona logging no mesmo estilo do webserver."""

    def on_connect(self):
        log("CONN", f"conectado  ←  {self.remote_ip}:{self.remote_port}")

    def on_disconnect(self):
        log("CONN", f"desconectado  ←  {self.remote_ip}")

    def on_login(self, username):
        log("LOGIN", f"{username}  ←  {self.remote_ip}")

    def on_login_failed(self, username, password):
        log("LOGIN", f"falha para usuário '{username}'  ←  {self.remote_ip}", ok=False)

    def on_logout(self, username):
        log("LOGOUT", f"{username}  ←  {self.remote_ip}")

    def on_file_sent(self, file):
        try:
            size = format_file_size(os.path.getsize(file))
        except OSError:
            size = "?"
        log("DOWNLOAD", f"{file}  ({size})  ←  {self.remote_ip}")

    def on_file_received(self, file):
        try:
            size = format_file_size(os.path.getsize(file))
        except OSError:
            size = "?"
        log("UPLOAD", f"{file}  ({size})  ←  {self.remote_ip}")

    def on_incomplete_file_sent(self, file):
        log("DOWNLOAD", f"{file}  incompleto  ←  {self.remote_ip}", ok=False)

    def on_incomplete_file_received(self, file):
        try:
            os.remove(file)  # não deixa lixo de upload incompleto/cancelado
        except OSError:
            pass
        log("UPLOAD", f"{file}  incompleto (removido)  ←  {self.remote_ip}", ok=False)

    def ftp_DELE(self, path):
        log("DELETE", f"arquivo  {path}  ←  {self.remote_ip}")
        return super().ftp_DELE(path)

    def ftp_RMD(self, path):
        log("DELETE", f"pasta  {path}  ←  {self.remote_ip}")
        return super().ftp_RMD(path)

    def ftp_MKD(self, path):
        log("MKDIR", f"{path}  ←  {self.remote_ip}")
        return super().ftp_MKD(path)

    def ftp_RNTO(self, path):
        log("MOVE", f"{self.fs.fs2ftp(self._rnfr) if getattr(self, '_rnfr', None) else '?'}  →  {path}  ←  {self.remote_ip}")
        return super().ftp_RNTO(path)


def setup_authorizer():
    authorizer = DummyAuthorizer()
    for username, password, homedir, perm in FTP_USERS:
        if not os.path.isdir(homedir):
            print(f"Diretório não encontrado para o usuário '{username}': {homedir}")
            sys.exit(1)
        authorizer.add_user(username, password, homedir, perm=perm)
    if ALLOW_ANONYMOUS:
        authorizer.add_anonymous(FTP_ROOT, perm=ANON_PERM)
    return authorizer


def main():
    handler = MyFTPHandler
    handler.authorizer = setup_authorizer()
    handler.passive_ports = PASSIVE_PORTS
    handler.banner = BANNER

    server = ThreadedFTPServer((FTP_HOST, FTP_PORT), handler)
    server.max_cons = MAX_CONNECTIONS
    server.max_cons_per_ip = MAX_CONNECTIONS_PER_IP

    users_str = ", ".join(u[0] for u in FTP_USERS) + (" + anônimo" if ALLOW_ANONYMOUS else "")
    print("╔══════════════════════════════════════════╗")
    print(f"║  Servidor FTP rodando na porta {FTP_PORT:<11}║")
    print(f"║  ftp://localhost:{FTP_PORT:<25}║")
    print(f"║  Usuários: {users_str:<32}║")
    print(f"║  Raiz: {FTP_ROOT:<36}║")
    print("╚══════════════════════════════════════════╝")

    try:
        server.serve_forever()
    except KeyboardInterrupt:
        print("\nDesligando...")
        server.close_all()


if __name__ == "__main__":
    main()
