from abc import ABC, abstractmethod

import structlog

logger = structlog.get_logger(__name__)


class InvoiceRepository(ABC):
    @abstractmethod
    def upload_invoice(self, invoice: str, filename: str):
        pass


class SFTPInvoiceRepository(InvoiceRepository):
    def __init__(self, hostname: str, username: str, password: str, port: int = 22):
        self.hostname = hostname
        self.username = username
        self.password = password
        self.port = port

    def upload_invoice(self, invoice: str, filename: str) -> None:
        from io import BytesIO

        from paramiko import AutoAddPolicy, SSHClient

        invoice_io = BytesIO(invoice.encode("utf-8"))
        ssh_client = SSHClient()

        try:
            ssh_client.set_missing_host_key_policy(AutoAddPolicy())
            ssh_client.connect(
                self.hostname,
                port=self.port,
                username=self.username,
                password=self.password,
            )

            with ssh_client.open_sftp() as sftp_client:
                sftp_client.putfo(invoice_io, f"uploads/{filename}")

        except Exception as e:
            logger.error("Could not upload invoice", exc_info=e)
        finally:
            ssh_client.close()
