<?php

namespace PortalPeople\indicator\commands;

use Yii;
use yii\console\Controller;
use yii\console\ExitCode;
use phpseclib3\Net\SFTP;
use PortalPeople\indicator\Module;
use PortalPeople\indicator\services\FtpDownloadService;
use PortalPeople\indicator\services\ProcessFilesService;

class IndicatorController extends Controller
{
    public function actionDownload($delete = false)
    {
        $this->stdout("Starting Indicator file download...\n");

        /** @var Module $module */
        $module = Yii::$app->getModule('indicator');
        if (!$module || !$module->isConfigured()) {
            $this->stderr("ERROR: Indicator module not configured\n");

            return ExitCode::CONFIG;
        }

        $inboxDir = Yii::getAlias('@runtime/indicator/inbox');
        if (!is_dir($inboxDir)) {
            @mkdir($inboxDir, 0755, true);
        }

        $service = new FtpDownloadService([
            'protocol'            => $module->protocol,
            'host'                => $module->host,
            'port'                => $module->port,
            'username'            => $module->username,
            'password'            => $module->password,
            'remotePath'          => $module->remotePath,
            'passiveMode'         => $module->passiveMode,
            'moveAfterDownload'   => $module->moveAfterDownload,
            'moveToPath'          => $module->moveToPath,
            'deleteAfterDownload' => (bool) $delete ?: $module->deleteAfterDownload,
            'inboxPath'           => $inboxDir,
        ]);

        $result = $service->download();

        $this->stdout("Downloaded: " . count($result['downloaded']) . " files\n");

        if (!empty($result['downloaded'])) {
            foreach ($result['downloaded'] as $file) {
                $this->stdout("  ✓ $file\n");
            }
        }

        if (!empty($result['errors'])) {
            $this->stderr("Errors:\n");
            foreach ($result['errors'] as $err) {
                $this->stderr("  ✗ $err\n");
            }

            return ExitCode::IOERR;
        }

        return ExitCode::OK;
    }

    public function actionProcess($dryRun = false)
    {
        $this->stdout("Starting Indicator file processing...\n");

        /** @var Module $module */
        $module = Yii::$app->getModule('indicator');
        if (!$module || !$module->isConfigured()) {
            $this->stderr("ERROR: Indicator module not configured\n");

            return ExitCode::CONFIG;
        }

        $inboxDir = Yii::getAlias('@runtime/indicator/inbox');
        $processedDir = Yii::getAlias('@runtime/indicator/processed');
        $failedDir = Yii::getAlias('@runtime/indicator/failed');

        foreach ([$inboxDir, $processedDir, $failedDir] as $dir) {
            if (!is_dir($dir)) {
                @mkdir($dir, 0755, true);
            }
        }

        $service = new ProcessFilesService([
            'inboxPath' => $inboxDir,
            'processedPath' => $processedDir,
            'failedPath' => $failedDir,
            'module' => $module,
        ]);

        $result = $service->process();

        $this->stdout("Processed: {$result['processed']} files\n");
        $this->stdout("Orders created: {$result['created']}\n");

        if ($result['failed'] > 0) {
            $this->stderr("Failed: {$result['failed']}\n");

            if (!empty($result['errors'])) {
                foreach ($result['errors'] as $err) {
                    $this->stderr("  {$err['file']}: {$err['error']}\n");
                }
            }
        }

        return $result['success'] ? ExitCode::OK : ExitCode::IOERR;
    }

    public function actionTest()
    {
        $this->stdout("Testing Indicator FTP connection...\n");

        /** @var Module $module */
        $module = Yii::$app->getModule('indicator');
        if (!$module) {
            $this->stderr("ERROR: Indicator module not loaded\n");

            return ExitCode::CONFIG;
        }

        if (!$module->isConfigured()) {
            $this->stderr("ERROR: Indicator module not configured\n");
            $this->stderr("Missing configuration in params-local.php under plugins.indicator\n");

            return ExitCode::CONFIG;
        }

        $this->stdout("Config found:\n");
        $this->stdout("  Protocol: {$module->protocol}\n");
        $this->stdout("  Host: {$module->host}\n");
        $this->stdout("  Port: {$module->port}\n");
        $this->stdout("  Path: {$module->remotePath}\n");
        $this->stdout("  Download interval: {$module->pickupIntervalSeconds}s\n");
        $this->stdout("  Process interval: {$module->processIntervalSeconds}s\n");
        $this->stdout("  Summary email: {$module->summaryEmail}\n\n");

        $this->stdout("Testing connection...\n");

        $service = new FtpDownloadService([
            'protocol' => $module->protocol,
            'host' => $module->host,
            'port' => $module->port,
            'username' => $module->username,
            'password' => $module->password,
            'remotePath' => $module->remotePath,
            'deleteAfterDownload' => false,
            'inboxPath' => Yii::getAlias('@runtime/indicator/inbox'),
        ]);

        $result = $service->download();

        if ($result['success'] || empty($result['errors'])) {
            $this->stdout("✓ Connection successful\n");

            return ExitCode::OK;
        } else {
            $this->stderr("✗ Connection failed\n");
            foreach ($result['errors'] as $err) {
                $this->stderr("  $err\n");
            }

            return ExitCode::IOERR;
        }
    }

    public function actionDebug()
    {
        $step = function (string $msg) { $this->stdout("  >> {$msg}\n"); };
        $ok   = function (string $msg) { $this->stdout("  ✓  {$msg}\n"); };
        $fail = function (string $msg) { $this->stderr("  ✗  {$msg}\n"); };

        $this->stdout("\n=== Indicator SFTP Debug ===\n\n");

        // 1. Module
        $step('Loading indicator module...');
        /** @var Module $module */
        $module = Yii::$app->getModule('indicator');
        if (!$module) {
            $fail('Module not loaded — is it registered in console config?');
            return ExitCode::CONFIG;
        }
        $ok('Module loaded');

        // 2. Config
        $step('Checking configuration...');
        $raw = Yii::$app->params['plugins']['indicator'] ?? null;
        $this->stdout("       Raw params key : " . ($raw ? 'found' : 'NOT FOUND — save config from the web UI first') . "\n");
        $this->stdout("       Enabled  : " . ($module->enabled ? 'yes' : 'NO (will be set to true on next save)') . "\n");
        $this->stdout("       Protocol : {$module->protocol}\n");
        $this->stdout("       Host     : " . ($module->host ?: '(empty)') . "\n");
        $this->stdout("       Port     : {$module->port}\n");
        $this->stdout("       User     : " . ($module->username ?: '(empty)') . "\n");
        $this->stdout("       Password : " . (empty($module->password) ? '(empty)' : str_repeat('*', min(strlen($module->password), 8)) . ' [' . strlen($module->password) . ' chars]') . "\n");
        $this->stdout("       Path     : " . ($module->remotePath ?: '(empty)') . "\n");
        if (empty($module->host) || empty($module->username)) {
            $fail('Host or username is empty — re-save configuration from the Indicator web UI');
            return ExitCode::CONFIG;
        }
        $ok('Config present');

        // 3. phpseclib available
        $step('Checking phpseclib3...');
        if (!class_exists(SFTP::class)) {
            $fail('phpseclib3\Net\SFTP class not found — run composer require phpseclib/phpseclib');
            return ExitCode::UNSPECIFIED_ERROR;
        }
        $ok('phpseclib3 available');

        // 4. DNS
        $step("Resolving host {$module->host}...");
        $ip = gethostbyname($module->host);
        if ($ip === $module->host) {
            $fail("DNS resolution failed for {$module->host}");
            return ExitCode::UNSPECIFIED_ERROR;
        }
        $ok("Resolved to {$ip}");

        // 5. TCP connect
        $step("TCP connect to {$ip}:{$module->port}...");
        $sock = @fsockopen($ip, $module->port, $errno, $errstr, 5);
        if (!$sock) {
            $fail("TCP connection refused: [{$errno}] {$errstr}");
            return ExitCode::UNSPECIFIED_ERROR;
        }
        fclose($sock);
        $ok('TCP port reachable');

        $protocol = strtolower(trim($module->protocol));

        if ($protocol === 'sftp') {
            // 6. SFTP object — disable Yii error handler so phpseclib internals don't throw
            $yiiHandler = set_error_handler(null);

            $step('Creating SFTP session...');
            try {
                $sftp = new SFTP($module->host, $module->port, 10);
                $ok('SFTP object created');
            } catch (\Throwable $e) {
                set_error_handler($yiiHandler);
                $fail('SFTP instantiation failed: ' . $e->getMessage());
                return ExitCode::UNSPECIFIED_ERROR;
            }

            // 7. Login
            $step("Authenticating as {$module->username}...");
            try {
                if (!$sftp->login($module->username, $module->password)) {
                    set_error_handler($yiiHandler);
                    $fail('Authentication failed — check username/password');
                    $this->stderr("       Last SFTP error: " . $sftp->getLastError() . "\n");
                    return ExitCode::UNSPECIFIED_ERROR;
                }
                $ok('Authenticated');
            } catch (\Throwable $e) {
                set_error_handler($yiiHandler);
                $fail('Login exception: ' . $e->getMessage());
                return ExitCode::UNSPECIFIED_ERROR;
            }

            // 8. chdir
            $step("Changing to remote path {$module->remotePath}...");
            if (!$sftp->chdir($module->remotePath)) {
                set_error_handler($yiiHandler);
                $fail("Cannot chdir to {$module->remotePath} — check path exists and user has permission");
                $this->stderr("       Last SFTP error: " . $sftp->getLastError() . "\n");
                return ExitCode::UNSPECIFIED_ERROR;
            }
            $ok('Path accessible');

            // 9. List files
            $step('Listing remote directory...');
            $files = $sftp->nlist('.');
            set_error_handler($yiiHandler);

            if (!is_array($files)) {
                $fail('nlist() returned no result — empty directory or permission denied');
            } else {
                $xmlFiles = array_filter($files, fn($f) => preg_match('/\.xml$/i', $f));
                $ok(count($files) . ' entries found, ' . count($xmlFiles) . ' XML file(s)');
                foreach ($xmlFiles as $f) {
                    $this->stdout("         - {$f}\n");
                }
            }
        } elseif ($protocol === 'ftp' || $protocol === 'ftps') {
            $useSsl = $protocol === 'ftps';
            $label  = $useSsl ? 'FTPS (explicit TLS)' : 'FTP';

            // 6. Connect
            $step("Connecting via {$label}...");
            $conn = $useSsl
                ? @ftp_ssl_connect($module->host, $module->port, 10)
                : @ftp_connect($module->host, $module->port, 10);
            if (!$conn) {
                $fail("Cannot connect to {$module->host}:{$module->port} via {$label}");
                return ExitCode::UNSPECIFIED_ERROR;
            }
            $ok('Connected');

            // 7. Login
            $step("Authenticating as {$module->username}...");
            if (!@ftp_login($conn, $module->username, $module->password)) {
                ftp_close($conn);
                $fail('Authentication failed — check username/password');
                return ExitCode::UNSPECIFIED_ERROR;
            }
            $ok('Authenticated');

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

            // 8. chdir
            $step("Changing to remote path {$module->remotePath}...");
            if (!@ftp_chdir($conn, $module->remotePath)) {
                ftp_close($conn);
                $fail("Cannot chdir to {$module->remotePath} — check path exists and user has permission");
                return ExitCode::UNSPECIFIED_ERROR;
            }
            $ok('Path accessible');

            // 9. List files
            $step('Listing remote directory...');
            $files = @ftp_nlist($conn, '.');
            ftp_close($conn);

            if (!is_array($files)) {
                $fail('ftp_nlist() returned no result — empty directory or permission denied');
            } else {
                $xmlFiles = array_filter($files, fn($f) => preg_match('/\.xml$/i', $f));
                $ok(count($files) . ' entries found, ' . count($xmlFiles) . ' XML file(s)');
                foreach ($xmlFiles as $f) {
                    $this->stdout("         - {$f}\n");
                }
            }
        } else {
            $fail("Unknown protocol '{$protocol}' — must be ftp, ftps, or sftp");
            return ExitCode::UNSPECIFIED_ERROR;
        }

        $this->stdout("\n=== Debug complete ===\n\n");

        return ExitCode::OK;
    }
}
