<?php

declare(strict_types=1);

namespace App\Http\Controllers\Customer;

use App\Domain\Account\Models\Account;
use App\Domain\Sysapi\Contracts\SysapiBridge;
use App\Domain\Sysapi\Exceptions\SysapiException;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Inertia\Inertia;
use Inertia\Response;
use Throwable;

/**
 * Customer Disk Usage Analyzer.
 *
 * sysapi('du-account') → /home/<username> üzerinde du -sb + top files / dirs.
 * Hata olursa DB'deki account.disk_usage_bytes değerine düşer ve UI'da
 * stale işareti gösterilir (mock breakdown ile değiştirilmedi — gerçek
 * sayısal değerler yoksa boş array döner).
 */
class DiskUsageController extends Controller
{
    public function __construct(
        private readonly SysapiBridge $sysapi,
    ) {}

    public function index(Request $request): Response
    {
        /** @var Account $account */
        $account = $request->attributes->get('customer_account');

        $payload = $this->fetchUsage($account);

        return Inertia::render('Customer/DiskUsage/Index', [
            'account' => [
                'username' => $account->username,
                'quota_bytes' => $account->quota_bytes,
                'usage_bytes' => $payload['total_bytes'] ?: $account->disk_usage_bytes,
                'usage_percent' => $account->diskUsagePercent(),
            ],
            'breakdown' => $payload['breakdown'],
            'top_files' => $payload['top_files'],
            'top_directories' => $payload['top_directories'],
            'stale' => $payload['stale'],
            'phase_warning' => $payload['stale']
                ? [
                    'level' => 'info',
                    'message' => 'Disk breakdown bu sunucuda hazır değil (dev / sysapi yok). Production hostingda du -sb üzerinden gerçek değerler gösterilir.',
                ]
                : null,
        ]);
    }

    /**
     * @return array{
     *   total_bytes:int,
     *   breakdown:array<int, array<string, mixed>>,
     *   top_files:array<int, array<string, mixed>>,
     *   top_directories:array<int, array<string, mixed>>,
     *   stale:bool
     * }
     */
    private function fetchUsage(Account $account): array
    {
        try {
            $result = $this->sysapi->run('du-account', [
                'username' => $account->username,
                'home' => '/home/' . $account->username,
                'top_count' => 20,
            ], timeoutSeconds: 45);
        } catch (SysapiException | Throwable) {
            return $this->emptyPayload();
        }

        if ($result->failed() || ! is_array($result->data)) {
            return $this->emptyPayload();
        }

        $data = $result->data;
        $breakdown = $this->formatBreakdown($data['breakdown'] ?? []);
        $topFiles = $this->formatTopFiles($data['top_files'] ?? []);
        $topDirs = $this->formatTopDirectories($data['top_directories'] ?? []);

        return [
            'total_bytes' => (int) ($data['total_bytes'] ?? 0),
            'breakdown' => $breakdown,
            'top_files' => $topFiles,
            'top_directories' => $topDirs,
            'stale' => false,
        ];
    }

    /**
     * @return array{total_bytes:int,breakdown:array,top_files:array,top_directories:array,stale:bool}
     */
    private function emptyPayload(): array
    {
        return [
            'total_bytes' => 0,
            'breakdown' => [],
            'top_files' => [],
            'top_directories' => [],
            'stale' => true,
        ];
    }

    /**
     * @param  array<string, int>  $raw
     * @return array<int, array<string, mixed>>
     */
    private function formatBreakdown(array $raw): array
    {
        $categories = [
            'public_html' => ['icon' => '🌐', 'color' => 'bg-blue-500', 'description' => 'Web sitesi dosyaları'],
            'Maildir' => ['icon' => '📧', 'color' => 'bg-rose-500', 'description' => 'E-posta kutuları (Maildir)'],
            'mail' => ['icon' => '📧', 'color' => 'bg-rose-500', 'description' => 'E-posta kutuları'],
            'databases' => ['icon' => '💾', 'color' => 'bg-cyan-500', 'description' => 'MySQL veritabanları'],
            'logs' => ['icon' => '📋', 'color' => 'bg-amber-500', 'description' => 'Apache access/error logları'],
            'backups' => ['icon' => '☁️', 'color' => 'bg-indigo-500', 'description' => 'Hesap yedekleri'],
            'tmp' => ['icon' => '🗑️', 'color' => 'bg-slate-400', 'description' => 'Geçici dosyalar'],
            'private' => ['icon' => '🔒', 'color' => 'bg-purple-500', 'description' => 'DocRoot dışı dosyalar'],
        ];

        $out = [];
        foreach ($raw as $name => $bytes) {
            if ((int) $bytes <= 0) {
                continue;
            }
            $meta = $categories[$name] ?? ['icon' => '📦', 'color' => 'bg-slate-500', 'description' => $name];
            $out[] = [
                'name' => $name,
                'icon' => $meta['icon'],
                'bytes' => (int) $bytes,
                'color' => $meta['color'],
                'description' => $meta['description'],
            ];
        }

        usort($out, static fn (array $a, array $b): int => $b['bytes'] <=> $a['bytes']);

        return $out;
    }

    /**
     * @param  array<int, array<string, mixed>>  $raw
     * @return array<int, array<string, mixed>>
     */
    private function formatTopFiles(array $raw): array
    {
        $out = [];
        foreach ($raw as $f) {
            if (! is_array($f) || ! isset($f['path'])) {
                continue;
            }
            $out[] = [
                'path' => (string) $f['path'],
                'bytes' => (int) ($f['size'] ?? $f['bytes'] ?? 0),
                'mime' => (string) ($f['mime'] ?? $this->guessMime((string) $f['path'])),
            ];
        }

        return $out;
    }

    /**
     * @param  array<int, array<string, mixed>>  $raw
     * @return array<int, array<string, mixed>>
     */
    private function formatTopDirectories(array $raw): array
    {
        $out = [];
        foreach ($raw as $d) {
            if (! is_array($d) || ! isset($d['path'])) {
                continue;
            }
            $out[] = [
                'path' => (string) $d['path'],
                'bytes' => (int) ($d['size'] ?? $d['bytes'] ?? 0),
                'file_count' => (int) ($d['file_count'] ?? 0),
            ];
        }

        return $out;
    }

    private function guessMime(string $path): string
    {
        $ext = strtolower(pathinfo($path, PATHINFO_EXTENSION));

        return match ($ext) {
            'jpg', 'jpeg' => 'image/jpeg',
            'png' => 'image/png',
            'gif' => 'image/gif',
            'mp4', 'mov' => 'video/mp4',
            'zip' => 'application/zip',
            'tar' => 'application/x-tar',
            'gz', 'tgz' => 'application/gzip',
            'sql' => 'application/sql',
            'log', 'txt' => 'text/plain',
            'html', 'htm' => 'text/html',
            'pdf' => 'application/pdf',
            default => 'application/octet-stream',
        };
    }
}
