<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

use App\Models\Certificate;
use App\Models\CaCertificate;
use App\Services\OpenSslService;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Response;
use Illuminate\Support\Facades\Config;
use ZipArchive;
use Illuminate\Support\Str;

class CertificateController extends Controller
{
    protected $sslService;

    public function __construct(OpenSslService $sslService)
    {
        $this->sslService = $sslService;
    }

    public function index(Request $request)
    {
        $caReady = CaCertificate::where('ca_type', 'root')->exists() && 
                   CaCertificate::where('ca_type', 'intermediate_2048')->exists() &&
                   CaCertificate::where('ca_type', 'intermediate_4096')->exists();
        
        $perPage = $request->input('per_page', 10);
        $search = $request->input('search');

        $query = Certificate::where('user_id', Auth::id());

        if ($search) {
            $query->where(function($q) use ($search) {
                $q->where('common_name', 'like', "%{$search}%")
                  ->orWhere('serial_number', 'like', "%{$search}%")
                  ->orWhere('san', 'like', "%{$search}%");
            });
        }

        $certificates = $query->latest()->paginate($perPage)->withQueryString();

        if ($request->ajax()) {
            return view('pages.certificate.partials.table', [
                'certificates' => $certificates,
            ])->render();
        }

        return view('pages.certificate.index', [
            'title' => 'Certificate Management',
            'caReady' => $caReady,
            'certificates' => $certificates,
            'perPage' => $perPage,
            'search' => $search,
            'defaults' => Config::get('openssl.ca_leaf_default')
        ]);
    }

    public function downloadCa($type)
    {
        // map legacy or simple type to specific ca_type
        $caType = match($type) {
            'root' => 'root',
            'intermediate', 'int_4096' => 'intermediate_4096',
            'int_2048' => 'intermediate_2048',
            default => $type
        };

        $ca = CaCertificate::where('ca_type', $caType)->firstOrFail();
        
        $configKey = match($caType) {
            'root' => 'openssl.ca_root.organizationName',
            'intermediate_4096' => 'openssl.ca_4096.organizationName',
            'intermediate_2048' => 'openssl.ca_2048.organizationName',
            default => 'app.name'
        };

        $orgName = config($configKey);
        $brand = Str::slug($orgName, '_');
        $filename = "{$brand}_ca_{$type}.crt";
        
        return response($ca->cert_content)
            ->header('Content-Type', 'application/x-x509-ca-cert')
            ->header('Content-Disposition', "attachment; filename={$filename}");
    }

    public function downloadCaBundle()
    {
        $root = CaCertificate::where('ca_type', 'root')->firstOrFail();
        $int2048 = CaCertificate::where('ca_type', 'intermediate_2048')->firstOrFail();
        $int4096 = CaCertificate::where('ca_type', 'intermediate_4096')->firstOrFail();
        
        // Bundle includes all for convenience
        $bundle = $int4096->cert_content . "\n" . $int2048->cert_content . "\n" . $root->cert_content;
        
        $brand = Str::slug(config('openssl.ca_root.organizationName'), '_');
        $filename = "{$brand}_ca-bundle.crt";

        return response($bundle)
            ->header('Content-Type', 'application/x-x509-ca-cert')
            ->header('Content-Disposition', "attachment; filename={$filename}");
    }

    public function downloadCaAndroid()
    {
        $root = CaCertificate::where('ca_type', 'root')->firstOrFail();
        
        // Convert PEM to DER
        $certPem = $root->cert_content;
        $begin = "-----BEGIN CERTIFICATE-----";
        $end = "-----END CERTIFICATE-----";
        $der = base64_decode($certPem);

        $brand = Str::slug(config('openssl.ca_root.organizationName'), '_');
        $filename = "{$brand}_root-ca.der";

        return response($der)
            ->header('Content-Type', 'application/pkix-cert')
            ->header('Content-Disposition', "attachment; filename={$filename}");
    }

    public function downloadInstaller()
    {
        $appUrl = config('app.url');
        $brand = Str::slug(config('openssl.ca_root.organizationName'), '_');
        
        $script = <<<BATCH
@echo off
setlocal

:: One-Click Certificate Installer for {$brand}
:: Generated by {$appUrl}

set "SERVER_URL={$appUrl}"
set "TEMP_DIR=%TEMP%\\{$brand}_installer"

if not exist "%TEMP_DIR%" mkdir "%TEMP_DIR%"
cd /d "%TEMP_DIR%"

echo [1/5] Downloading Root CA...
curl -s -f -o "root.crt" "%SERVER_URL%/certificate/download-ca/root"
if %errorlevel% neq 0 (
    echo Failed to download Root CA.
    pause
    exit /b %errorlevel%
)

echo [2/5] Downloading Intermediate CA 2048...
curl -s -f -o "int_2048.crt" "%SERVER_URL%/certificate/download-ca/int_2048"
if %errorlevel% neq 0 (
    echo Failed to download Intermediate CA 2048.
    pause
    exit /b %errorlevel%
)

echo [3/5] Downloading Intermediate CA 4096...
curl -s -f -o "int_4096.crt" "%SERVER_URL%/certificate/download-ca/int_4096"
if %errorlevel% neq 0 (
    echo Failed to download Intermediate CA 4096.
    pause
    exit /b %errorlevel%
)

echo [4/5] Installing Root CA to Trusted Root Certification Authorities...
certutil -user -addstore "Root" "root.crt"

echo [5/5] Installing Intermediate CAs to Intermediate Certification Authorities...
certutil -user -addstore "CA" "int_2048.crt"
certutil -user -addstore "CA" "int_4096.crt"

echo.
echo Cleanup...
cd ..
rmdir /s /q "%TEMP_DIR%"

echo.
echo ========================================================
echo Installation Complete!
echo You may need to restart your browser dynamically.
echo ========================================================
pause
BATCH;

        return response($script)
            ->header('Content-Type', 'application/x-msdos-program')
            ->header('Content-Disposition', "attachment; filename={$brand}_install_certs.bat");
    }

    public function create()
    {
        return view('pages.certificate.create', [
            'title' => 'Generate Certificate',
            'defaults' => Config::get('openssl.ca_leaf_default')
        ]);
    }

    public function setupCa()
    {
        if (CaCertificate::count() > 0) {
            return redirect()->route('certificate.index')->with('error', 'CA already initialized.');
        }

        if ($this->sslService->setupCa()) {
            return redirect()->route('certificate.index')->with('success', 'Root and Intermediate CA successfully initialized.');
        }

        return redirect()->route('certificate.index')->with('error', 'Failed to initialize CA.');
    }

    public function generate(Request $request)
    {
        $validated = $request->validate([
            'common_name' => 'required|string|max:255',
            'config_mode' => 'required|in:default,manual',
            'organization' => 'nullable|required_if:config_mode,manual|string|max:255',
            'locality' => 'nullable|required_if:config_mode,manual|string|max:255',
            'state' => 'nullable|required_if:config_mode,manual|string|max:255',
            'country' => 'nullable|required_if:config_mode,manual|string|size:2',
            'san' => 'nullable|string',
            'key_bits' => 'required|in:2048,4096',
        ]);

        try {
            // Apply defaults if mode is 'default'
            if ($validated['config_mode'] === 'default') {
                $defaults = Config::get('openssl.ca_leaf_default');
                $validated['organization'] = $defaults['organizationName'];
                $validated['locality'] = $defaults['localityName'];
                $validated['state'] = $defaults['stateOrProvinceName'];
                $validated['country'] = $defaults['countryName'];
            }

            $result = $this->sslService->generateLeaf($validated);

            Certificate::create([
                'user_id' => Auth::id(),
                'common_name' => $validated['common_name'],
                'organization' => $validated['organization'],
                'locality' => $validated['locality'],
                'state' => $validated['state'],
                'country' => $validated['country'],
                'san' => $validated['san'],
                'key_bits' => $validated['key_bits'],
                'serial_number' => $this->sslService->formatSerialToHex($result['serial']),
                'cert_content' => $result['cert'],
                'key_content' => $result['key'],
                'csr_content' => $result['csr'],
                'valid_from' => $result['valid_from'] ?? null,
                'valid_to' => $result['valid_to'] ?? null,
            ]);

            return redirect()->route('certificate.index')->with('success', 'Certificate generated successfully.');
        } catch (\Exception $e) {
            return redirect()->back()->withInput()->with('error', $e->getMessage());
        }
    }
    public function regenerate(Certificate $certificate)
    {
        $this->authorizeOwner($certificate);

        try {
            $data = [
                'common_name' => $certificate->common_name,
                'organization' => $certificate->organization,
                'locality' => $certificate->locality,
                'state' => $certificate->state,
                'country' => $certificate->country,
                'san' => $certificate->san,
                'key_bits' => $certificate->key_bits,
            ];

            $result = $this->sslService->generateLeaf($data);

            // Update existing record with new content
            $certificate->update([
                'serial_number' => $this->sslService->formatSerialToHex($result['serial']),
                'cert_content' => $result['cert'],
                'key_content' => $result['key'],
                'csr_content' => $result['csr'],
                'valid_from' => $result['valid_from'] ?? null,
                'valid_to' => $result['valid_to'] ?? null,
                'created_at' => now(), // Refresh timestamp
            ]);

            return redirect()->route('certificate.index')->with('success', 'Certificate regenerated successfully.');
        } catch (\Exception $e) {
            return redirect()->route('certificate.index')->with('error', 'Failed to regenerate: ' . $e->getMessage());
        }
    }


    public function downloadZip(Certificate $certificate)
    {
        $this->authorizeOwner($certificate);

        $tempFile = tempnam(sys_get_temp_dir(), 'cert_zip');
        $zip = new ZipArchive;
        
        if ($zip->open($tempFile, ZipArchive::CREATE | ZipArchive::OVERWRITE) !== TRUE) {
            return redirect()->back()->with('error', 'Failed to create ZIP archive.');
        }
        
        $filenameBase = preg_replace('/[^a-zA-Z0-9-_\.]/', '_', $certificate->common_name);
        
        $zip->addFromString("{$filenameBase}.pem", $certificate->cert_content);
        $zip->addFromString("{$filenameBase}.key", $certificate->key_content);
        if ($certificate->csr_content) {
            $zip->addFromString("{$filenameBase}.csr", $certificate->csr_content);
        }
        $zip->close();

        return response()->download($tempFile, "cert_{$filenameBase}.zip")->deleteFileAfterSend(true);
    }

    public function downloadP12(Certificate $certificate)
    {
        $this->authorizeOwner($certificate);

        $password = '112133'; // Default password from user request
        if (openssl_pkcs12_export($certificate->cert_content, $p12, $certificate->key_content, $password)) {
            $filenameBase = preg_replace('/[^a-zA-Z0-9-_\.]/', '_', $certificate->common_name);
            return response($p12)
                ->header('Content-Type', 'application/x-pkcs12')
                ->header('Content-Disposition', "attachment; filename={$filenameBase}.p12");
        }

        return redirect()->back()->with('error', 'Failed to generate P12 file.');
    }

    public function viewFile(Certificate $certificate, $type)
    {
        $this->authorizeOwner($certificate);

        $content = match($type) {
            'cert' => $certificate->cert_content,
            'key' => $certificate->key_content,
            'csr' => $certificate->csr_content,
            default => abort(404)
        };

        return response($content)->header('Content-Type', 'text/plain');
    }

    public function delete(Certificate $certificate)
    {
        $this->authorizeOwner($certificate);
        $certificate->delete();
        return redirect()->route('certificate.index')->with('success', 'Certificate deleted successfully.');
    }

    protected function authorizeOwner(Certificate $certificate)
    {
        if ($certificate->user_id !== Auth::id()) {
            abort(403);
        }
    }
}
