<?php

namespace PortalPeople\zupa\services;

use Yii;
use yii\base\BaseObject;

class FtpDownloadService extends BaseObject
{
    public string $protocol = 'sftp';
    public string $host = '';
    public int $port = 22;
    public string $username = '';
    public string $password = '';
    public string $remotePath = '/';
    public bool $deleteAfterDownload = false;
    public bool $passiveMode = true;
    public string $inboxPath = '';

    public function download(): array
    {
        $result = [
            'success' => false,
            'downloaded' => [],
            'errors' => [],
        ];

        try {
            $protocol = strtolower(trim($this->protocol));

            if ($protocol === 'ftp') {
                return $this->downloadFtp();
            } elseif ($protocol === 'sftp') {
                return $this->downloadSftp();
            } else {
                throw new \RuntimeException("Unsupported protocol: {$this->protocol}");
            }
        } catch (\Throwable $e) {
            Yii::error('FTP download failed: ' . $e->getMessage(), 'zupa.download');
            $result['errors'][] = $e->getMessage();

            return $result;
        }
    }

    private function downloadFtp(): array
    {
        $result = [
            'success' => false,
            'downloaded' => [],
            'errors' => [],
        ];

        $conn = ftp_connect($this->host, $this->port, 10);
        if (!$conn) {
            $result['errors'][] = "Failed to connect to {$this->host}:{$this->port}";

            return $result;
        }

        if (!@ftp_login($conn, $this->username, $this->password)) {
            ftp_close($conn);
            $result['errors'][] = 'FTP authentication failed';

            return $result;
        }

        if ($this->passiveMode) {
            ftp_pasv($conn, true);
        }

        if (!@ftp_chdir($conn, $this->remotePath)) {
            ftp_close($conn);
            $result['errors'][] = "Cannot change to remote path: {$this->remotePath}";

            return $result;
        }

        $files = @ftp_nlist($conn, '.');
        if (!is_array($files)) {
            $files = [];
        }

        foreach ($files as $file) {
            $file = basename($file);
            if (preg_match('/\.xml$/i', $file)) {
                $localFile = $this->inboxPath . DIRECTORY_SEPARATOR . $file;

                if (@ftp_get($conn, $localFile, $file, FTP_BINARY)) {
                    $result['downloaded'][] = $file;

                    if ($this->deleteAfterDownload) {
                        @ftp_delete($conn, $file);
                    }
                } else {
                    $result['errors'][] = "Failed to download: {$file}";
                }
            }
        }

        ftp_close($conn);
        $result['success'] = empty($result['errors']);

        return $result;
    }

    private function downloadSftp(): array
    {
        $result = [
            'success' => false,
            'downloaded' => [],
            'errors' => [],
        ];

        if (!extension_loaded('ssh2')) {
            $result['errors'][] = 'PHP ssh2 extension is not installed';

            return $result;
        }

        $conn = @ssh2_connect($this->host, $this->port);
        if (!$conn) {
            $result['errors'][] = "Failed to connect to {$this->host}:{$this->port}";

            return $result;
        }

        if (!@ssh2_auth_password($conn, $this->username, $this->password)) {
            $result['errors'][] = 'SFTP authentication failed';

            return $result;
        }

        $sftp = @ssh2_sftp($conn);
        if (!$sftp) {
            $result['errors'][] = 'Failed to initialize SFTP subsystem';

            return $result;
        }

        $remotePath = 'ssh2.sftp://' . intval($sftp) . $this->remotePath;
        $dir = @opendir($remotePath);
        if (!$dir) {
            $result['errors'][] = "Cannot open remote path: {$this->remotePath}";

            return $result;
        }

        while (($file = readdir($dir)) !== false) {
            if ($file === '.' || $file === '..') {
                continue;
            }

            if (preg_match('/\.xml$/i', $file)) {
                $remoteFile = rtrim($this->remotePath, '/') . '/' . $file;
                $localFile = $this->inboxPath . DIRECTORY_SEPARATOR . $file;

                if (@ssh2_scp_recv($conn, $remoteFile, $localFile)) {
                    $result['downloaded'][] = $file;

                    if ($this->deleteAfterDownload) {
                        $stat = @ssh2_sftp_stat($sftp, $remoteFile);
                        if (is_array($stat)) {
                            @ssh2_sftp_unlink($sftp, $remoteFile);
                        }
                    }
                } else {
                    $result['errors'][] = "Failed to download: {$file}";
                }
            }
        }

        closedir($dir);
        unset($sftp);
        unset($conn);

        $result['success'] = empty($result['errors']);

        return $result;
    }
}
