﻿<?php

use App\Models\MpesaSetting;
use App\Services\MpesaService;
use Illuminate\Support\Facades\Auth;
use Livewire\Attributes\Title;
use Livewire\Component;
use Throwable;

new #[Title('M-PESA Setup')] class extends Component
{
    public string $environment = 'sandbox';

    public string $consumer_key = '';

    public string $consumer_secret = '';

    public string $shortcode = '';

    public string $passkey = '';

    public string $transaction_type = 'CustomerPayBillOnline';

    public string $callback_url = '';

    public string $sandbox_phone_number = '';

    public bool $enabled = false;

    public bool $hasSavedCredentials = false;

    public string $connectionStatus = '';

    public string $connectionMessage = '';

    public function mount(): void
    {
        abort_unless(
            Auth::user()?->isPlatformAdmin(),
            403
        );

        $settings = MpesaSetting::query()->first();

        if (! $settings) {
            $this->callback_url = route('mpesa.stk.callback');

            return;
        }

        $this->environment = $settings->environment ?: 'sandbox';
        $this->shortcode = $settings->shortcode ?? '';
        $this->transaction_type =
            $settings->transaction_type
            ?: 'CustomerPayBillOnline';

        $this->callback_url =
            $settings->callback_url
            ?: route('mpesa.stk.callback');

        $this->sandbox_phone_number =
            $settings->sandbox_phone_number ?? '';

        $this->enabled = $settings->enabled;

        $this->hasSavedCredentials =
            filled($settings->consumer_key)
            && filled($settings->consumer_secret)
            && filled($settings->passkey);
    }

    public function useChamaHubCallbackUrl(): void
    {
        abort_unless(
            Auth::user()?->isPlatformAdmin(),
            403
        );

        $this->callback_url = route('mpesa.stk.callback');
        $this->connectionStatus = '';
        $this->connectionMessage = '';
    }

    public function save(): void
    {
        $this->saveSettings(true);
    }

    public function testConnection(): void
    {
        abort_unless(
            Auth::user()?->isPlatformAdmin(),
            403
        );

        $this->connectionStatus = '';
        $this->connectionMessage = '';

        $this->saveSettings(false);

        try {
            app(MpesaService::class)->accessToken();

            $this->connectionStatus = 'success';
            $this->connectionMessage =
                'M-PESA connection successful.';
        } catch (Throwable $exception) {
            report($exception);

            $this->connectionStatus = 'error';
            $this->connectionMessage =
                'M-PESA connection test failed. Check the environment '
                . 'and Daraja credentials.';
        }
    }

    public function credentialsReady(): bool
    {
        $settings = MpesaSetting::query()->first();

        if (! $settings) {
            return false;
        }

        return filled($settings->consumer_key)
            && filled($settings->consumer_secret)
            && filled($settings->passkey)
            && filled($settings->shortcode);
    }

    public function callbackReady(): bool
    {
        if (! filled($this->callback_url)) {
            return false;
        }

        return filter_var(
            $this->callback_url,
            FILTER_VALIDATE_URL
        ) !== false;
    }

    public function productionCallbackReady(): bool
    {
        if (! $this->callbackReady()) {
            return false;
        }

        $parts = parse_url($this->callback_url);

        $scheme = strtolower(
            $parts['scheme'] ?? ''
        );

        $host = strtolower(
            $parts['host'] ?? ''
        );

        $path = strtolower(
            $parts['path'] ?? ''
        );

        if ($scheme !== 'https') {
            return false;
        }

        if ($host === ''
            || in_array(
                $host,
                [
                    'localhost',
                    '127.0.0.1',
                    '0.0.0.0',
                ],
                true
            )
        ) {
            return false;
        }

        if (str_contains($path, 'mpesa')) {
            return false;
        }

        return true;
    }

    public function automaticCallbackUrl(): string
    {
        return route('mpesa.stk.callback');
    }

    private function saveSettings(bool $showSuccess): void
    {
        abort_unless(
            Auth::user()?->isPlatformAdmin(),
            403
        );

        $validated = $this->validate([
            'environment' => [
                'required',
                'in:sandbox,production',
            ],
            'consumer_key' => [
                'nullable',
                'string',
                'max:500',
            ],
            'consumer_secret' => [
                'nullable',
                'string',
                'max:500',
            ],
            'shortcode' => [
                'required',
                'string',
                'max:50',
            ],
            'passkey' => [
                'nullable',
                'string',
                'max:500',
            ],
            'transaction_type' => [
                'required',
                'in:CustomerPayBillOnline,CustomerBuyGoodsOnline',
            ],
            'callback_url' => [
                'required',
                'url',
                'max:1000',
            ],
            'sandbox_phone_number' => [
                'nullable',
                'string',
                'max:20',
            ],
            'enabled' => [
                'boolean',
            ],
        ]);

        $settings = MpesaSetting::query()->firstOrNew();

        $existingCredentialsReady =
            filled($settings->consumer_key)
            && filled($settings->consumer_secret)
            && filled($settings->passkey);

        if ($validated['enabled']) {
            if (
                ! $existingCredentialsReady
                && (
                    ! filled($validated['consumer_key'])
                    || ! filled($validated['consumer_secret'])
                    || ! filled($validated['passkey'])
                )
            ) {
                $this->addError(
                    'consumer_key',
                    'Consumer key, consumer secret and passkey '
                    . 'are required before M-PESA can be enabled.'
                );

                return;
            }
        }

        if ($validated['environment'] === 'production') {
            $parts = parse_url(
                $validated['callback_url']
            );

            $scheme = strtolower(
                $parts['scheme'] ?? ''
            );

            $host = strtolower(
                $parts['host'] ?? ''
            );

            $path = strtolower(
                $parts['path'] ?? ''
            );

            if ($scheme !== 'https') {
                $this->addError(
                    'callback_url',
                    'Production M-PESA callbacks must use HTTPS.'
                );

                return;
            }

            if (
                $host === ''
                || in_array(
                    $host,
                    [
                        'localhost',
                        '127.0.0.1',
                        '0.0.0.0',
                    ],
                    true
                )
            ) {
                $this->addError(
                    'callback_url',
                    'Production M-PESA callbacks must use a '
                    . 'public domain.'
                );

                return;
            }

            if (str_contains($path, 'mpesa')) {
                $this->addError(
                    'callback_url',
                    'Use a neutral callback path such as '
                    . '/api/payments/stk/callback.'
                );

                return;
            }
        }

        $settings->environment =
            $validated['environment'];

        $settings->shortcode =
            $validated['shortcode'];

        $settings->transaction_type =
            $validated['transaction_type'];

        $settings->callback_url =
            $validated['callback_url'];

        $settings->sandbox_phone_number =
            $validated['sandbox_phone_number'];

        $settings->enabled =
            $validated['enabled'];

        if (filled($validated['consumer_key'])) {
            $settings->consumer_key =
                $validated['consumer_key'];
        }

        if (filled($validated['consumer_secret'])) {
            $settings->consumer_secret =
                $validated['consumer_secret'];
        }

        if (filled($validated['passkey'])) {
            $settings->passkey =
                $validated['passkey'];
        }

        $settings->save();

        $this->consumer_key = '';
        $this->consumer_secret = '';
        $this->passkey = '';

        $this->hasSavedCredentials =
            filled($settings->consumer_key)
            && filled($settings->consumer_secret)
            && filled($settings->passkey);

        if ($showSuccess) {
            session()->flash(
                'success',
                'M-PESA settings saved successfully.'
            );
        }
    }
};
?>

<x-pages::settings.layout
    :heading="__('M-PESA Setup')"
    :subheading="__('Configure and test the M-PESA payment gateway without editing configuration files.')"
>
    <div class="space-y-6">
        @if (session('success'))
            <div class="rounded-xl border border-green-200 bg-green-50 p-4 text-sm text-green-800 dark:border-green-900/60 dark:bg-green-950/30 dark:text-green-300">
                {{ session('success') }}
            </div>
        @endif

        @if ($connectionStatus === 'success')
            <div class="rounded-xl border border-green-200 bg-green-50 p-4 text-sm text-green-800 dark:border-green-900/60 dark:bg-green-950/30 dark:text-green-300">
                {{ $connectionMessage }}
            </div>
        @elseif ($connectionStatus === 'error')
            <div class="rounded-xl border border-red-200 bg-red-50 p-4 text-sm text-red-800 dark:border-red-900/60 dark:bg-red-950/30 dark:text-red-300">
                {{ $connectionMessage }}
            </div>
        @endif

        <div class="rounded-xl border border-zinc-200 bg-white p-5 shadow-sm dark:border-zinc-700 dark:bg-zinc-900">
            <div class="flex items-start justify-between gap-4">
                <div>
                    <h2 class="text-base font-semibold text-zinc-900 dark:text-white">
                        Setup status
                    </h2>

                    <p class="mt-1 text-sm text-zinc-500 dark:text-zinc-400">
                        Complete these checks before enabling live M-PESA payments.
                    </p>
                </div>

                <span
                    class="rounded-full px-3 py-1 text-xs font-semibold {{ $enabled ? 'bg-green-100 text-green-700 dark:bg-green-950/40 dark:text-green-300' : 'bg-zinc-100 text-zinc-600 dark:bg-zinc-800 dark:text-zinc-300' }}"
                >
                    {{ $enabled ? 'Enabled' : 'Disabled' }}
                </span>
            </div>

            <div class="mt-5 grid gap-3 sm:grid-cols-3">
                <div class="rounded-lg border border-zinc-200 p-4 dark:border-zinc-700">
                    <p class="text-xs font-medium uppercase tracking-wide text-zinc-500 dark:text-zinc-400">
                        Credentials
                    </p>

                    <p class="mt-2 text-sm font-semibold {{ $this->credentialsReady() ? 'text-green-600 dark:text-green-400' : 'text-amber-600 dark:text-amber-400' }}">
                        {{ $this->credentialsReady() ? 'Ready' : 'Needs setup' }}
                    </p>
                </div>

                <div class="rounded-lg border border-zinc-200 p-4 dark:border-zinc-700">
                    <p class="text-xs font-medium uppercase tracking-wide text-zinc-500 dark:text-zinc-400">
                        Callback
                    </p>

                    <p class="mt-2 text-sm font-semibold {{ $this->callbackReady() ? 'text-green-600 dark:text-green-400' : 'text-amber-600 dark:text-amber-400' }}">
                        {{ $this->callbackReady() ? 'Configured' : 'Needs setup' }}
                    </p>
                </div>

                <div class="rounded-lg border border-zinc-200 p-4 dark:border-zinc-700">
                    <p class="text-xs font-medium uppercase tracking-wide text-zinc-500 dark:text-zinc-400">
                        Production
                    </p>

                    <p class="mt-2 text-sm font-semibold {{ $environment === 'production' ? ($this->productionCallbackReady() ? 'text-green-600 dark:text-green-400' : 'text-amber-600 dark:text-amber-400') : 'text-zinc-600 dark:text-zinc-300' }}">
                        {{ $environment === 'production' ? ($this->productionCallbackReady() ? 'Ready for callback check' : 'Production callback needed') : 'Sandbox mode' }}
                    </p>
                </div>
            </div>
        </div>

        <div class="rounded-xl border border-blue-200 bg-blue-50 p-5 text-sm text-blue-900 dark:border-blue-900/60 dark:bg-blue-950/30 dark:text-blue-200">
            <p class="font-semibold">
                Easy installation
            </p>

            <p class="mt-1">
                M-PESA credentials entered here are saved encrypted.
                The installer does not need to edit the application
                configuration file manually.
            </p>
        </div>

        <form wire:submit="save" class="space-y-6">
            <div class="rounded-xl border border-zinc-200 bg-white p-6 shadow-sm dark:border-zinc-700 dark:bg-zinc-900">
                <h2 class="text-base font-semibold text-zinc-900 dark:text-white">
                    1. Environment
                </h2>

                <div class="mt-5 space-y-5">
                    <flux:field>
                        <flux:label>{{ __('Environment') }}</flux:label>

                        <flux:select wire:model.live="environment">
                            <flux:select.option value="sandbox">
                                {{ __('Sandbox') }}
                            </flux:select.option>

                            <flux:select.option value="production">
                                {{ __('Production') }}
                            </flux:select.option>
                        </flux:select>

                        <flux:error name="environment" />
                    </flux:field>

                    <flux:field>
                        <flux:label>{{ __('Business Shortcode') }}</flux:label>

                        <flux:input
                            wire:model="shortcode"
                            type="text"
                            inputmode="numeric"
                            autocomplete="off"
                            placeholder="174379"
                        />

                        <flux:description>
                            PayBill or Till shortcode supplied for your M-PESA integration.
                        </flux:description>

                        <flux:error name="shortcode" />
                    </flux:field>

                    <flux:field>
                        <flux:label>{{ __('Transaction Type') }}</flux:label>

                        <flux:select wire:model="transaction_type">
                            <flux:select.option value="CustomerPayBillOnline">
                                CustomerPayBillOnline
                            </flux:select.option>

                            <flux:select.option value="CustomerBuyGoodsOnline">
                                CustomerBuyGoodsOnline
                            </flux:select.option>
                        </flux:select>

                        <flux:error name="transaction_type" />
                    </flux:field>
                </div>
            </div>

            <div class="rounded-xl border border-zinc-200 bg-white p-6 shadow-sm dark:border-zinc-700 dark:bg-zinc-900">
                <div class="flex flex-col gap-3 sm:flex-row sm:items-start sm:justify-between">
                    <div>
                        <h2 class="text-base font-semibold text-zinc-900 dark:text-white">
                            2. Callback
                        </h2>

                        <p class="mt-1 text-sm text-zinc-500 dark:text-zinc-400">
                            This is where Safaricom sends payment results.
                        </p>
                    </div>

                    <button
                        type="button"
                        wire:click="useChamaHubCallbackUrl"
                        class="text-sm font-semibold text-indigo-600 hover:text-indigo-700 dark:text-indigo-400"
                    >
                        Use ChamaHub callback URL
                    </button>
                </div>

                <div class="mt-5">
                    <flux:field>
                        <flux:label>{{ __('Callback URL') }}</flux:label>

                        <flux:input
                            wire:model="callback_url"
                            type="url"
                            autocomplete="url"
                        />

                        <flux:description>
                            {{ $this->automaticCallbackUrl() }}
                        </flux:description>

                        <flux:error name="callback_url" />
                    </flux:field>
                </div>

                @if ($environment === 'production' && ! $this->productionCallbackReady())
                    <div class="mt-4 rounded-lg border border-amber-200 bg-amber-50 p-4 text-sm text-amber-800 dark:border-amber-900/60 dark:bg-amber-950/30 dark:text-amber-300">
                        Production requires a public HTTPS callback URL.
                        A permanent domain must be configured before live payments are enabled.
                    </div>
                @endif
            </div>

            <div class="rounded-xl border border-zinc-200 bg-white p-6 shadow-sm dark:border-zinc-700 dark:bg-zinc-900">
                <h2 class="text-base font-semibold text-zinc-900 dark:text-white">
                    3. Daraja credentials
                </h2>

                <p class="mt-1 text-sm text-zinc-500 dark:text-zinc-400">
                    {{ $hasSavedCredentials ? 'Credentials are already saved. Leave these fields blank to keep them unchanged.' : 'Enter the credentials supplied by the M-PESA/Daraja integration.' }}
                </p>

                <div class="mt-5 space-y-5">
                    <flux:field>
                        <flux:label>{{ __('Consumer Key') }}</flux:label>

                        <flux:input
                            wire:model="consumer_key"
                            type="password"
                            autocomplete="new-password"
                            placeholder="{{ $hasSavedCredentials ? __('Saved - enter only to replace') : __('Enter consumer key') }}"
                        />

                        <flux:error name="consumer_key" />
                    </flux:field>

                    <flux:field>
                        <flux:label>{{ __('Consumer Secret') }}</flux:label>

                        <flux:input
                            wire:model="consumer_secret"
                            type="password"
                            autocomplete="new-password"
                            placeholder="{{ $hasSavedCredentials ? __('Saved - enter only to replace') : __('Enter consumer secret') }}"
                        />

                        <flux:error name="consumer_secret" />
                    </flux:field>

                    <flux:field>
                        <flux:label>{{ __('Passkey') }}</flux:label>

                        <flux:input
                            wire:model="passkey"
                            type="password"
                            autocomplete="new-password"
                            placeholder="{{ $hasSavedCredentials ? __('Saved - enter only to replace') : __('Enter passkey') }}"
                        />

                        <flux:error name="passkey" />
                    </flux:field>
                </div>
            </div>

            <div class="rounded-xl border border-zinc-200 bg-white p-6 shadow-sm dark:border-zinc-700 dark:bg-zinc-900">
                <h2 class="text-base font-semibold text-zinc-900 dark:text-white">
                    4. Sandbox testing
                </h2>

                <div class="mt-5 space-y-5">
                    <flux:field>
                        <flux:label>{{ __('Sandbox Test Phone Number') }}</flux:label>

                        <flux:input
                            wire:model="sandbox_phone_number"
                            type="tel"
                            inputmode="numeric"
                            placeholder="254712345678"
                            autocomplete="tel"
                        />

                        <flux:description>
                            Optional. Used when testing against the sandbox environment.
                        </flux:description>

                        <flux:error name="sandbox_phone_number" />
                    </flux:field>

                    <flux:field>
                        <flux:switch wire:model="enabled">
                            {{ __('Allow M-PESA payments') }}
                        </flux:switch>

                        <flux:error name="enabled" />
                    </flux:field>
                </div>
            </div>

            <div class="flex flex-wrap items-center gap-3">
                <flux:button
                    type="submit"
                    variant="primary"
                    wire:loading.attr="disabled"
                >
                    {{ __('Save M-PESA Settings') }}
                </flux:button>

                <flux:button
                    type="button"
                    wire:click="testConnection"
                    wire:loading.attr="disabled"
                    variant="ghost"
                >
                    {{ __('Test Connection') }}
                </flux:button>

                <flux:button
                    type="button"
                    variant="ghost"
                    href="{{ route('profile.edit') }}"
                    wire:navigate
                >
                    {{ __('Cancel') }}
                </flux:button>
            </div>
        </form>
    </div>
</x-pages::settings.layout>
