<?php

namespace App\Http\Controllers\Notification;

use App\Http\Controllers\ApiController;
use App\Http\Requests\Notification\IndexNotificationRequest;
use App\Http\Requests\Notification\SaveNotificationPreferencesRequest;
use App\Http\Requests\Notification\StoreCustomerContactRequest;
use App\Http\Requests\Notification\StoreNotificationBroadcastRequest;
use App\Http\Requests\Notification\StoreNotificationChannelRequest;
use App\Http\Requests\Notification\StoreNotificationTemplateRequest;
use App\Http\Requests\Notification\StoreSystemNotificationRequest;
use App\Http\Resources\Notification\NotificationDeliveryResource;
use App\Http\Resources\Notification\SystemNotificationCampaignResource;
use App\Models\Customer;
use App\Models\CustomerContact;
use App\Models\NotificationBroadcast;
use App\Models\NotificationChannel;
use App\Models\NotificationEvent;
use App\Models\NotificationTemplate;
use App\Services\Notification\NotificationService;
use App\Services\Notification\WhapiIdService;
use Illuminate\Http\Request;

class NotificationController extends ApiController
{
    public function __construct(protected NotificationService $service, protected WhapiIdService $whapi) {}

    public function events()
    {
        return $this->success(NotificationEvent::where('enabled', true)->orderBy('category')->orderBy('name')->get(), 'Daftar event notifikasi berhasil diambil');
    }

    public function channels(Request $request)
    {
        return $this->success($this->service->channels($this->channel($request), $request->user(), $this->tenantId($request)), 'Konfigurasi channel berhasil diambil');
    }

    public function systemCampaigns(IndexNotificationRequest $request)
    {
        return $this->successPaginated(
            $this->service->systemCampaigns($request->validated(), $request->user(), $this->tenantId($request)),
            SystemNotificationCampaignResource::class,
            'Riwayat notifikasi System berhasil diambil'
        );
    }

    public function storeSystemCampaign(StoreSystemNotificationRequest $request)
    {
        return $this->created(
            $this->service->createSystemCampaign($request->validated(), $request->user(), $this->tenantId($request)),
            'Notifikasi System masuk antrean'
        );
    }

    public function systemAudienceOptions(Request $request)
    {
        $data = $request->validate([
            'tenant_id' => ['nullable', 'integer', 'exists:tenants,id'],
            'search' => ['nullable', 'string', 'max:100'],
        ]);

        return $this->success(
            $this->service->systemAudienceOptions(
                $request->user(), $this->tenantId($request), $data['tenant_id'] ?? null, $data['search'] ?? null
            ),
            'Pilihan penerima notifikasi berhasil diambil'
        );
    }

    public function storeChannel(StoreNotificationChannelRequest $request)
    {
        abort_unless($request->validated('channel') === $this->channel($request), 422);
        $this->authorizeChannelMutation($request);

        return $this->created($this->service->saveChannel($request->validated(), $request->user(), $this->tenantId($request)), 'Konfigurasi channel berhasil dibuat');
    }

    public function updateChannel(StoreNotificationChannelRequest $request, NotificationChannel $notificationChannel)
    {
        $this->authorizeTenant($request, $notificationChannel->tenant_id);
        abort_unless($notificationChannel->channel === $this->channel($request), 404);
        $this->authorizeChannelMutation($request);

        return $this->updated($this->service->saveChannel($request->validated(), $request->user(), $this->tenantId($request), $notificationChannel), 'Konfigurasi channel berhasil diperbarui');
    }

    public function testChannel(Request $request, NotificationChannel $notificationChannel)
    {
        $this->authorizeTenant($request, $notificationChannel->tenant_id);
        abort_unless($notificationChannel->channel === $this->channel($request), 404);
        $this->authorizeChannelMutation($request);

        return $this->success($this->service->testChannel($notificationChannel), 'Pengujian channel selesai');
    }

    public function destroyChannel(Request $request, NotificationChannel $notificationChannel)
    {
        $this->authorizeTenant($request, $notificationChannel->tenant_id);
        abort_unless($notificationChannel->channel === $this->channel($request), 404);
        $this->authorizeChannelMutation($request);
        $this->service->deleteChannel($notificationChannel);

        return $this->deleted('Konfigurasi channel berhasil dinonaktifkan atau dihapus');
    }

    public function whapiState(Request $request, NotificationChannel $notificationChannel)
    {
        $this->authorizeWhapiAccess($request, $notificationChannel);

        return $this->success($this->whapi->state($notificationChannel), 'Status perangkat WHAPI berhasil diambil');
    }

    public function whapiStart(Request $request, NotificationChannel $notificationChannel)
    {
        $this->authorizeWhapiAccess($request, $notificationChannel);

        return $this->success($this->whapi->start($notificationChannel), 'Layanan WHAPI berhasil dijalankan');
    }

    public function whapiQr(Request $request, NotificationChannel $notificationChannel)
    {
        $this->authorizeWhapiAccess($request, $notificationChannel);

        return $this->success($this->whapi->qr($notificationChannel), 'QR WHAPI berhasil diambil');
    }

    public function whapiTestMessage(Request $request, NotificationChannel $notificationChannel)
    {
        $this->authorizeWhapiAccess($request, $notificationChannel);
        $data = $request->validate([
            'phone' => ['required', 'string', 'max:25', 'regex:/^\+?[0-9][0-9\s\-()]{7,24}$/'],
            'message' => ['required', 'string', 'max:4000'],
        ]);

        return $this->success(
            $this->whapi->send($notificationChannel, $data['phone'], $data['message']),
            'Pesan uji WHAPI berhasil dikirim'
        );
    }

    public function templates(Request $request)
    {
        return $this->success($this->service->templates($this->channel($request), $request->user(), $this->tenantId($request)), 'Daftar template berhasil diambil');
    }

    public function storeTemplate(StoreNotificationTemplateRequest $request)
    {
        abort_unless($request->validated('channel') === $this->channel($request), 422);

        return $this->created($this->service->saveTemplate($request->validated(), $request->user(), $this->tenantId($request)), 'Template berhasil dibuat');
    }

    public function updateTemplate(StoreNotificationTemplateRequest $request, NotificationTemplate $notificationTemplate)
    {
        if ($notificationTemplate->tenant_id) {
            $this->authorizeTenant($request, $notificationTemplate->tenant_id);
        }
        abort_unless($notificationTemplate->channel === $this->channel($request), 404);

        return $this->updated($this->service->saveTemplate($request->validated(), $request->user(), $this->tenantId($request), $notificationTemplate), 'Template berhasil diperbarui');
    }

    public function preferences(Request $request)
    {
        $tenantId = $request->user()->isMasterAdmin() && $request->integer('tenant_id')
            ? $request->integer('tenant_id')
            : $this->tenantId($request);

        return $this->success($this->service->preferences($request->user(), $tenantId), 'Preference notifikasi berhasil diambil');
    }

    public function savePreferences(SaveNotificationPreferencesRequest $request)
    {
        $this->service->savePreferences($request->validated('preferences'), $request->user(), $this->tenantId($request));

        return $this->updated(null, 'Preference notifikasi berhasil disimpan');
    }

    public function deliveries(IndexNotificationRequest $request)
    {
        return $this->successPaginated(
            $this->service->deliveries($this->channel($request), $request->validated(), $request->user(), $this->tenantId($request)),
            NotificationDeliveryResource::class,
            'Log pesan berhasil diambil',
        );
    }

    public function broadcasts(IndexNotificationRequest $request)
    {
        return $this->success($this->service->broadcasts($request->validated(), $request->user(), $this->tenantId($request)), 'Daftar pesan siaran berhasil diambil');
    }

    public function previewBroadcast(StoreNotificationBroadcastRequest $request)
    {
        return $this->success($this->service->previewBroadcast($request->validated(), $request->user(), $this->tenantId($request)), 'Preview penerima berhasil dihitung');
    }

    public function storeBroadcast(StoreNotificationBroadcastRequest $request)
    {
        return $this->created($this->service->createBroadcast($request->validated(), $request->user(), $this->tenantId($request)), 'Pesan siaran masuk antrean');
    }

    public function showBroadcast(Request $request, NotificationBroadcast $notificationBroadcast)
    {
        $this->authorizeTenant($request, $notificationBroadcast->tenant_id);

        return $this->success($notificationBroadcast->load(['template', 'channelConfig', 'recipients.customer:id,customer_code,name']), 'Detail siaran berhasil diambil');
    }

    public function approveBroadcast(Request $request, NotificationBroadcast $notificationBroadcast)
    {
        $this->authorizeTenant($request, $notificationBroadcast->tenant_id);

        return $this->updated($this->service->approveBroadcast($notificationBroadcast, $request->user()), 'Pesan siaran berhasil disetujui');
    }

    public function myNotifications(IndexNotificationRequest $request)
    {
        return $this->success($this->service->userNotifications($request->user(), $request->validated()), 'Notifikasi aplikasi berhasil diambil');
    }

    public function markRead(Request $request, string $uuid)
    {
        $notification = $request->user()->userNotifications()->where('uuid', $uuid)->firstOrFail();
        $notification->update(['read_at' => now()]);

        return $this->updated($notification, 'Notifikasi ditandai sudah dibaca');
    }

    public function contacts(Request $request, Customer $customer)
    {
        $this->authorizeTenant($request, $customer->tenant_id);

        return $this->success($customer->contacts()->orderBy('type')->orderByDesc('is_primary')->get(), 'Kontak notifikasi berhasil diambil');
    }

    public function storeContact(StoreCustomerContactRequest $request, Customer $customer)
    {
        $this->authorizeTenant($request, $customer->tenant_id);

        return $this->created($this->service->saveContact($customer, $request->validated()), 'Kontak notifikasi berhasil dibuat');
    }

    public function updateContact(StoreCustomerContactRequest $request, Customer $customer, CustomerContact $contact)
    {
        $this->authorizeTenant($request, $customer->tenant_id);

        return $this->updated($this->service->saveContact($customer, $request->validated(), $contact), 'Kontak notifikasi berhasil diperbarui');
    }

    public function destroyContact(Request $request, Customer $customer, CustomerContact $contact)
    {
        $this->authorizeTenant($request, $customer->tenant_id);
        abort_unless((int) $contact->customer_id === (int) $customer->id, 404);
        $contact->delete();

        return $this->deleted('Kontak notifikasi berhasil dihapus');
    }

    private function channel(Request $request): string
    {
        return $request->route()->defaults['notification_channel'];
    }

    private function tenantId(Request $request): ?int
    {
        return $request->attributes->get('tenant_id');
    }

    private function authorizeTenant(Request $request, ?int $tenantId): void
    {
        abort_unless($request->user()->isMasterAdmin()
            || ($tenantId !== null && $tenantId === $this->tenantId($request)), 403);
    }

    private function authorizeChannelMutation(Request $request): void
    {
        if ($this->channel($request) === 'whatsapp_unofficial') {
            abort_unless($request->user()->isMasterAdmin(), 403, 'WhatsApp Unofficial hanya dapat dikonfigurasi oleh Master Admin.');
        }
    }

    private function authorizeWhapiAccess(Request $request, NotificationChannel $channel): void
    {
        abort_unless($channel->channel === 'whatsapp_unofficial' && $channel->provider === 'whapi_id', 404);
        abort_unless($request->user()->isMasterAdmin()
            || ((int) $channel->tenant_id === (int) $this->tenantId($request)
                && $request->user()->isTenantOwner($this->tenantId($request))), 403);
    }
}
