<?php

declare(strict_types=1);

namespace App\Services\Provisioning;

use App\Models\ProvisioningLog;
use App\Models\Service;
use App\Notifications\ServiceCredentialsNotification;
use Illuminate\Http\Client\PendingRequest;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log;
use Laravel\Cashier\Subscription;
use RuntimeException;

class EnhanceService implements ProvisioningServiceInterface
{
    private readonly string $baseUrl;

    private readonly string $token;

    public function __construct()
    {
        // Read from database settings (configured via admin panel)
        $this->baseUrl = rtrim(\App\Models\Setting::get('enhance_api_url', ''), '/');
        $this->token = \App\Models\Setting::get('enhance_api_token', '');
    }

    public function provision(Subscription $subscription): Service
    {
        $plan = $subscription->plan;
        $user = $subscription->user;

        if (! $plan) {
            throw new RuntimeException('Subscription has no associated plan.');
        }

        $service = Service::firstOrCreate(
            ['subscription_id' => $subscription->id, 'service_type' => 'hosting'],
            [
                'user_id' => $user->id,
                'plan_id' => $plan->id,
                'platform' => 'enhance',
                'status' => 'pending',
            ],
        );

        if ($service->status === 'failed') {
            $service->update(['status' => 'pending']);
        }

        $this->logAction($service, 'provision', 'pending');

        try {
            $response = $this->client()->post('/api/v1/websites', [
                'plan_id' => $plan->features['enhance_plan_id'] ?? null,
                'domain' => $plan->features['default_domain'] ?? 'hosting.ezscale.cloud',
                'customer_email' => $user->email,
            ]);

            if (! $response->successful()) {
                $this->logAction($service, 'provision', 'failed', $response->json(), $response->body());

                throw new RuntimeException("Enhance provisioning failed: {$response->body()}");
            }

            $data = $response->json();
            $websiteId = (string) ($data['data']['id'] ?? $data['id'] ?? '');

            $service->update([
                'platform_service_id' => $websiteId,
                'status' => 'active',
                'domain' => $data['data']['domain'] ?? $data['domain'] ?? null,
                'ipv4_address' => $data['data']['ip_address'] ?? $data['ip_address'] ?? null,
                'provisioned_at' => now(),
            ]);

            $this->logAction($service, 'provision', 'success', $data);

            $service = $service->fresh();

            if ($service->user) {
                $service->user->notify(new ServiceCredentialsNotification($service, [
                    'username' => $data['data']['username'] ?? $user->email,
                    'password' => $data['data']['password'] ?? 'see control panel',
                    'hostname' => $service->domain ?? $service->ipv4_address ?? 'N/A',
                    'ip_address' => $service->ipv4_address ?? 'Pending',
                    'port' => null,
                    'panel_url' => $data['data']['control_panel_url'] ?? null,
                ]));
            }

            return $service;
        } catch (RuntimeException $e) {
            throw $e;
        } catch (\Exception $e) {
            $this->logAction($service, 'provision', 'failed', errorMessage: $e->getMessage());

            $service->update(['status' => 'failed']);

            throw new RuntimeException("Enhance provisioning error: {$e->getMessage()}", 0, $e);
        }
    }

    public function suspend(Service $service): bool
    {
        $this->validateServicePlatform($service);

        $this->logAction($service, 'suspend', 'pending');

        try {
            $response = $this->client()->post("/api/v1/websites/{$service->platform_service_id}/suspend");

            if (! $response->successful()) {
                $this->logAction($service, 'suspend', 'failed', $response->json(), $response->body());

                return false;
            }

            $service->update([
                'status' => 'suspended',
                'suspended_at' => now(),
            ]);

            $this->logAction($service, 'suspend', 'success', $response->json());

            return true;
        } catch (\Exception $e) {
            Log::error('Enhance suspend failed', [
                'service_id' => $service->id,
                'error' => $e->getMessage(),
            ]);

            $this->logAction($service, 'suspend', 'failed', errorMessage: $e->getMessage());

            return false;
        }
    }

    public function unsuspend(Service $service): bool
    {
        $this->validateServicePlatform($service);

        $this->logAction($service, 'unsuspend', 'pending');

        try {
            $response = $this->client()->post("/api/v1/websites/{$service->platform_service_id}/unsuspend");

            if (! $response->successful()) {
                $this->logAction($service, 'unsuspend', 'failed', $response->json(), $response->body());

                return false;
            }

            $service->update([
                'status' => 'active',
                'suspended_at' => null,
            ]);

            $this->logAction($service, 'unsuspend', 'success', $response->json());

            return true;
        } catch (\Exception $e) {
            Log::error('Enhance unsuspend failed', [
                'service_id' => $service->id,
                'error' => $e->getMessage(),
            ]);

            $this->logAction($service, 'unsuspend', 'failed', errorMessage: $e->getMessage());

            return false;
        }
    }

    public function terminate(Service $service): bool
    {
        $this->validateServicePlatform($service);

        $this->logAction($service, 'terminate', 'pending');

        try {
            $response = $this->client()->delete("/api/v1/websites/{$service->platform_service_id}");

            if (! $response->successful()) {
                $this->logAction($service, 'terminate', 'failed', $response->json(), $response->body());

                return false;
            }

            $service->update([
                'status' => 'terminated',
                'terminated_at' => now(),
            ]);

            $this->logAction($service, 'terminate', 'success', $response->json());

            return true;
        } catch (\Exception $e) {
            Log::error('Enhance terminate failed', [
                'service_id' => $service->id,
                'error' => $e->getMessage(),
            ]);

            $this->logAction($service, 'terminate', 'failed', errorMessage: $e->getMessage());

            return false;
        }
    }

    /**
     * @return array{status: string, ip_address?: string, hostname?: string, platform_data?: array<string, mixed>}
     */
    public function getStatus(Service $service): array
    {
        $this->validateServicePlatform($service);

        try {
            $response = $this->client()->get("/api/v1/websites/{$service->platform_service_id}");

            if (! $response->successful()) {
                return ['status' => 'unknown'];
            }

            $data = $response->json();
            $websiteData = $data['data'] ?? $data;

            return [
                'status' => $websiteData['status'] ?? 'unknown',
                'ip_address' => $websiteData['ip_address'] ?? $service->ipv4_address,
                'hostname' => $websiteData['domain'] ?? $service->domain,
                'platform_data' => $websiteData,
            ];
        } catch (\Exception $e) {
            Log::error('Enhance getStatus failed', [
                'service_id' => $service->id,
                'error' => $e->getMessage(),
            ]);

            return ['status' => 'unknown'];
        }
    }

    /**
     * @return array{username?: string, password?: string, url?: string, additional?: array<string, mixed>}
     */
    public function getCredentials(Service $service): array
    {
        $this->validateServicePlatform($service);

        $stored = $service->credentials ?? [];

        try {
            $response = $this->client()->get("/api/v1/websites/{$service->platform_service_id}");

            if ($response->successful()) {
                $data = $response->json();
                $websiteData = $data['data'] ?? $data;

                return [
                    'username' => $stored['username'] ?? null,
                    'password' => $stored['password'] ?? null,
                    'url' => $websiteData['control_panel_url'] ?? null,
                    'additional' => [
                        'domain' => $websiteData['domain'] ?? $service->domain,
                        'ip_address' => $websiteData['ip_address'] ?? $service->ipv4_address,
                        'nameservers' => $websiteData['nameservers'] ?? [],
                    ],
                ];
            }
        } catch (\Exception $e) {
            Log::error('Enhance getCredentials failed', [
                'service_id' => $service->id,
                'error' => $e->getMessage(),
            ]);
        }

        return [
            'username' => $stored['username'] ?? null,
            'password' => $stored['password'] ?? null,
        ];
    }

    private function client(): PendingRequest
    {
        return Http::withToken($this->token)
            ->baseUrl($this->baseUrl)
            ->acceptJson()
            ->timeout(30);
    }

    private function validateServicePlatform(Service $service): void
    {
        if (! $service->platform_service_id) {
            throw new RuntimeException('Service has no platform service ID.');
        }
    }

    /**
     * @param  array<string, mixed>|null  $response
     */
    private function logAction(
        Service $service,
        string $action,
        string $status,
        ?array $response = null,
        ?string $errorMessage = null,
    ): void {
        ProvisioningLog::create([
            'service_id' => $service->id,
            'user_id' => $service->user_id,
            'action' => $action,
            'platform' => 'enhance',
            'platform_response' => $response,
            'status' => $status,
            'error_message' => $errorMessage,
        ]);
    }
}
