<?php

namespace App\Http\Controllers\Admin;

use App\Http\Controllers\Controller;
use App\Models\Business;
use App\Models\DailyBranchReport;
use App\Models\DailyBranchReportDelivery;
use App\Models\DailyBranchReportRecipient;
use App\Models\Setting;
use App\Services\AuditService;
use App\Services\DailyBranchReportService;
use App\Support\PhoneNumber;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Validation\Rule;
use Illuminate\Validation\ValidationException;
use Illuminate\View\View;

class DailyBranchReportController extends Controller
{
    public function index(): View
    {
        $business = Business::firstOrCreate(['id' => 1], ['name' => 'Microfinance']);
        $settings = Setting::query()
            ->where('business_id', $business->id)
            ->where('group', 'daily_reports')
            ->pluck('value', 'key');
        $branches = $business->branches()->orderBy('name')->get();
        $recipients = DailyBranchReportRecipient::query()
            ->with('branch')
            ->where('business_id', $business->id)
            ->orderBy('channel')
            ->orderBy('branch_id')
            ->orderBy('name')
            ->get();
        $reports = DailyBranchReport::query()
            ->with(['branch', 'dailyClosing.managerConfirmer', 'deliveries'])
            ->where('business_id', $business->id)
            ->latest('report_date')
            ->latest('id')
            ->paginate(20)
            ->withQueryString();
        $whatsappTokenConfigured = filled($business->whatsapp_api_token);

        return view('admin.settings.daily-reports', compact(
            'business', 'settings', 'branches', 'recipients', 'reports', 'whatsappTokenConfigured'
        ));
    }

    public function updateSettings(Request $request): RedirectResponse
    {
        $business = Business::firstOrCreate(['id' => 1], ['name' => 'Microfinance']);
        $whatsappEnabled = $request->boolean('whatsapp_enabled');
        $tokenConfigured = filled($business->whatsapp_api_token);

        $data = $request->validate([
            'email_enabled' => ['nullable', 'boolean'],
            'whatsapp_enabled' => ['nullable', 'boolean'],
            'whatsapp_api_endpoint' => [
                Rule::requiredIf($whatsappEnabled),
                'nullable', 'url', 'max:2048',
            ],
            'whatsapp_api_token' => [
                Rule::requiredIf($whatsappEnabled && ! $tokenConfigured),
                'nullable', 'string', 'max:4096',
            ],
        ]);

        $emailEnabled = $request->boolean('email_enabled');
        foreach ([
            'email_enabled' => $emailEnabled,
            'whatsapp_enabled' => $whatsappEnabled,
        ] as $key => $enabled) {
            Setting::updateOrCreate(
                ['business_id' => $business->id, 'group' => 'daily_reports', 'key' => $key],
                ['value' => $enabled ? '1' : '0', 'type' => 'boolean'],
            );
        }

        $businessChanges = [
            'whatsapp_api_endpoint' => trim((string) ($data['whatsapp_api_endpoint'] ?? '')) ?: null,
        ];
        $tokenUpdated = filled($data['whatsapp_api_token'] ?? null);
        if ($tokenUpdated) {
            $businessChanges['whatsapp_api_token'] = (string) $data['whatsapp_api_token'];
        }
        $business->update($businessChanges);

        AuditService::record('daily_branch_reports.settings.updated', $business, [], [
            'email_enabled' => $emailEnabled,
            'whatsapp_enabled' => $whatsappEnabled,
            'whatsapp_api_endpoint' => $businessChanges['whatsapp_api_endpoint'],
            'whatsapp_token_updated' => $tokenUpdated,
        ]);

        return back()->with('success', 'Daily branch report delivery settings updated.');
    }

    public function storeRecipient(Request $request): RedirectResponse
    {
        $business = Business::firstOrCreate(['id' => 1], ['name' => 'Microfinance']);
        $data = $this->validateRecipient($request, $business);
        $destination = $this->normalizeDestination($data['channel'], $data['destination'], $business);
        $branchId = $data['branch_id'] ?? null;

        $existing = DailyBranchReportRecipient::withTrashed()
            ->where('business_id', $business->id)
            ->where('branch_id', $branchId)
            ->where('channel', $data['channel'])
            ->where('destination', $destination)
            ->first();

        if ($existing && ! $existing->trashed()) {
            throw ValidationException::withMessages(['destination' => 'This recipient is already configured for the selected branch and channel.']);
        }

        if ($existing?->trashed()) {
            $existing->restore();
            $existing->update([
                'name' => $data['name'] ?? null,
                'is_active' => $request->boolean('is_active', true),
                'created_by' => $request->user()->id,
            ]);
            $recipient = $existing;
        } else {
            $recipient = DailyBranchReportRecipient::create([
                'business_id' => $business->id,
                'branch_id' => $branchId,
                'name' => $data['name'] ?? null,
                'channel' => $data['channel'],
                'destination' => $destination,
                'is_active' => $request->boolean('is_active', true),
                'created_by' => $request->user()->id,
            ]);
        }

        AuditService::record('daily_branch_reports.recipient.created', $recipient, [], $recipient->toArray(), $branchId);

        return back()->with('success', 'Report recipient added.');
    }

    public function updateRecipient(Request $request, DailyBranchReportRecipient $recipient): RedirectResponse
    {
        $business = Business::firstOrCreate(['id' => 1], ['name' => 'Microfinance']);
        abort_unless($recipient->business_id === $business->id, 404);
        $before = $recipient->toArray();
        $data = $this->validateRecipient($request, $business);
        $destination = $this->normalizeDestination($data['channel'], $data['destination'], $business);
        $branchId = $data['branch_id'] ?? null;

        $duplicate = DailyBranchReportRecipient::query()
            ->where('business_id', $business->id)
            ->where('branch_id', $branchId)
            ->where('channel', $data['channel'])
            ->where('destination', $destination)
            ->whereKeyNot($recipient->id)
            ->exists();
        if ($duplicate) {
            throw ValidationException::withMessages(['destination' => 'This recipient is already configured for the selected branch and channel.']);
        }

        $recipient->update([
            'branch_id' => $branchId,
            'name' => $data['name'] ?? null,
            'channel' => $data['channel'],
            'destination' => $destination,
            'is_active' => $request->boolean('is_active'),
        ]);

        AuditService::record('daily_branch_reports.recipient.updated', $recipient, $before, $recipient->fresh()->toArray(), $branchId);

        return back()->with('success', 'Report recipient updated.');
    }

    public function destroyRecipient(DailyBranchReportRecipient $recipient): RedirectResponse
    {
        $business = Business::firstOrCreate(['id' => 1], ['name' => 'Microfinance']);
        abort_unless($recipient->business_id === $business->id, 404);
        $before = $recipient->toArray();
        $branchId = $recipient->branch_id;
        $recipient->delete();

        AuditService::record('daily_branch_reports.recipient.deleted', $recipient, $before, [], $branchId);

        return back()->with('success', 'Report recipient removed. Existing report delivery history was preserved.');
    }

    public function show(DailyBranchReport $report): View
    {
        $business = Business::firstOrCreate(['id' => 1], ['name' => 'Microfinance']);
        abort_unless($report->business_id === $business->id, 404);
        $report->load(['branch', 'dailyClosing.managerConfirmer', 'deliveries.configuredRecipient']);

        return view('admin.settings.daily-report-show', compact('report'));
    }

    public function send(DailyBranchReport $report, DailyBranchReportService $service): RedirectResponse
    {
        $business = Business::firstOrCreate(['id' => 1], ['name' => 'Microfinance']);
        abort_unless($report->business_id === $business->id, 404);
        $service->resend($report);
        AuditService::record('daily_branch_reports.delivery.requested', $report, [], ['report_id' => $report->id], $report->branch_id);

        return back()->with('success', 'Enabled report deliveries were queued. Failed deliveries will be retried.');
    }

    public function retryDelivery(DailyBranchReportDelivery $delivery, DailyBranchReportService $service): RedirectResponse
    {
        $delivery->loadMissing('report');
        $business = Business::firstOrCreate(['id' => 1], ['name' => 'Microfinance']);
        abort_unless($delivery->report->business_id === $business->id, 404);
        $service->retry($delivery);
        AuditService::record('daily_branch_reports.delivery.retry_requested', $delivery, [], [
            'channel' => $delivery->channel,
            'recipient' => $delivery->recipient,
        ], $delivery->report->branch_id);

        return back()->with('success', 'Report delivery retry queued.');
    }

    private function validateRecipient(Request $request, Business $business): array
    {
        $channel = (string) $request->input('channel');
        $destinationRules = $channel === 'email'
            ? ['required', 'email:rfc', 'max:255']
            : ['required', 'string', 'max:50'];

        return $request->validate([
            'name' => ['nullable', 'string', 'max:255'],
            'branch_id' => [
                'nullable', 'integer',
                Rule::exists('branches', 'id')->where('business_id', $business->id),
            ],
            'channel' => ['required', Rule::in(DailyBranchReportRecipient::CHANNELS)],
            'destination' => $destinationRules,
            'is_active' => ['nullable', 'boolean'],
        ]);
    }

    private function normalizeDestination(string $channel, string $destination, Business $business): string
    {
        if ($channel === 'email') {
            return mb_strtolower(trim($destination));
        }

        $normalized = PhoneNumber::normalize($destination, $business->phone_country_code);
        if ($normalized === null) {
            throw ValidationException::withMessages([
                'destination' => 'Enter a valid WhatsApp phone number for the configured business country code.',
            ]);
        }

        return $normalized;
    }
}
