<?php

namespace Modules\WhatsApp\Http\Controllers;

use App\BusinessLocation;
use Illuminate\Http\Request;
use Illuminate\Routing\Controller;
use Modules\WhatsApp\Entities\Services\ChannelHealthService;
use Modules\WhatsApp\Entities\Services\WaSender;
use Modules\WhatsApp\Entities\WaChannel;

class WaChannelController extends Controller
{
    public function index()
    {
        $this->authorizeManage();
        $businessId = request()->session()->get('user.business_id');

        $channels = WaChannel::where('business_id', $businessId)
            ->orderByDesc('is_default')->orderBy('label')->get();

        $locations = BusinessLocation::where('business_id', $businessId)
            ->pluck('name', 'id');

        $health = new ChannelHealthService();
        $pending = [];
        foreach ($channels as $channel) {
            $pending[$channel->id] = $health->pendingCount($channel);
        }

        return view('whatsapp::channels.index', compact('channels', 'locations', 'pending'));
    }

    public function store(Request $request)
    {
        $this->authorizeManage();
        $businessId = request()->session()->get('user.business_id');

        $data = $this->validateChannel($request);

        $channel = new WaChannel();
        $channel->business_id = $businessId;
        $this->fill($channel, $data);

        if ($channel->driver === 'web') {
            $channel->api_token = WaChannel::freshToken();
            $channel->status = 'connecting';
        } else {
            // Meta Cloud API is always-on once credentials are present.
            $channel->status = $channel->isSendable() ? 'active' : 'connecting';
        }

        $this->applyDefault($channel, $request, $businessId);
        $channel->save();

        return redirect()->route('whatsapp.channels.index')->with('status', [
            'success' => 1, 'msg' => __('whatsapp::lang.saved'),
        ]);
    }

    public function update(Request $request, $id)
    {
        $this->authorizeManage();
        $businessId = request()->session()->get('user.business_id');

        $channel = WaChannel::where('business_id', $businessId)->findOrFail($id);
        $data = $this->validateChannel($request, $channel);
        $this->fill($channel, $data);

        if ($channel->driver === 'meta') {
            $channel->status = $channel->isSendable() ? 'active' : 'connecting';
        }

        $this->applyDefault($channel, $request, $businessId);
        $channel->save();

        return redirect()->route('whatsapp.channels.index')->with('status', [
            'success' => 1, 'msg' => __('whatsapp::lang.saved'),
        ]);
    }

    public function destroy($id)
    {
        $this->authorizeManage();
        $businessId = request()->session()->get('user.business_id');

        WaChannel::where('business_id', $businessId)->findOrFail($id)->delete();

        return redirect()->route('whatsapp.channels.index')->with('status', [
            'success' => 1, 'msg' => __('whatsapp::lang.saved'),
        ]);
    }

    /** QR pairing screen for WhatsApp-Web channels. */
    public function connect($id)
    {
        $this->authorizeManage();
        $businessId = request()->session()->get('user.business_id');

        $channel = WaChannel::where('business_id', $businessId)->findOrFail($id);
        abort_unless($channel->driver === 'web', 404);

        // Reset to a state where the bridge will offer a fresh QR.
        if ($channel->status !== 'active') {
            $channel->forceFill(['status' => 'connecting'])->save();
        }

        return view('whatsapp::channels.connect', compact('channel'));
    }

    /** Polled by the connect screen: returns the live status + latest QR. */
    public function qr($id)
    {
        $this->authorizeManage();
        $businessId = request()->session()->get('user.business_id');

        $channel = WaChannel::where('business_id', $businessId)->findOrFail($id);

        $qr = $channel->status === 'active' ? null : $channel->qr_code;

        return response()->json([
            'status'       => $channel->status,
            'status_label' => $channel->status_label,
            'qr'           => $qr,
            // Server-rendered QR so the page needs no external CDN / JS library.
            'qr_svg'       => $qr ? $this->renderQrSvg($qr) : null,
            'connected_as' => $channel->connected_as,
            'online'       => $channel->isBridgeOnline(),
        ]);
    }

    /** Render a QR payload to an inline SVG using the bundled milon/barcode. */
    private function renderQrSvg(string $payload): ?string
    {
        try {
            return (new \Milon\Barcode\DNS2D())->getBarcodeSVG($payload, 'QRCODE', 4, 4, 'black');
        } catch (\Throwable $e) {
            \Log::warning('WhatsApp QR SVG render failed: ' . $e->getMessage());
            return null;
        }
    }

    /** Tell the bridge (via state) to log out; here we just reset the channel. */
    public function logout($id)
    {
        $this->authorizeManage();
        $businessId = request()->session()->get('user.business_id');

        $channel = WaChannel::where('business_id', $businessId)->findOrFail($id);
        $channel->forceFill([
            'status'       => 'disconnected',
            'connected_as' => null,
            'session_meta' => null,
            'qr_code'      => null,
        ])->save();

        return back()->with('status', ['success' => 1, 'msg' => __('whatsapp::lang.saved')]);
    }

    public function regenerateToken($id)
    {
        $this->authorizeManage();
        $businessId = request()->session()->get('user.business_id');

        $channel = WaChannel::where('business_id', $businessId)->findOrFail($id);
        $channel->forceFill(['api_token' => WaChannel::freshToken()])->save();

        return back()->with('status', ['success' => 1, 'msg' => __('whatsapp::lang.regenerate_token')]);
    }

    public function sendTest(Request $request, $id)
    {
        $this->authorizeManage();
        $businessId = request()->session()->get('user.business_id');

        $request->validate(['to' => 'required|string|max:30']);
        $channel = WaChannel::where('business_id', $businessId)->findOrFail($id);

        (new WaSender())->send([
            'business_id' => $businessId,
            'channel_id'  => $channel->id,
            'to'          => $request->input('to'),
            'body'        => 'Test message from ' . config('app.name') . ' ✅',
            'source'      => 'test',
            'created_by'  => auth()->id(),
        ]);

        return back()->with('status', ['success' => 1, 'msg' => __('whatsapp::lang.send_test')]);
    }

    // ----- helpers -----

    private function authorizeManage(): void
    {
        if (!auth()->user()->can('whatsapp.manage_channels')) {
            abort(403, 'Unauthorized action.');
        }
    }

    private function validateChannel(Request $request, ?WaChannel $channel = null): array
    {
        return $request->validate([
            'label'                => 'required|string|max:120',
            'driver'               => 'required|in:meta,web',
            'location_id'          => 'nullable|integer',
            'display_number'       => 'nullable|string|max:30',
            'meta_phone_number_id' => 'nullable|string|max:60',
            'meta_waba_id'         => 'nullable|string|max:60',
            'meta_access_token'    => 'nullable|string',
            'meta_verify_token'    => 'nullable|string|max:80',
        ]);
    }

    private function fill(WaChannel $channel, array $data): void
    {
        $channel->label          = $data['label'];
        $channel->driver         = $data['driver'];
        $channel->location_id    = $data['location_id'] ?? null;
        $channel->display_number = $data['display_number'] ?? null;

        if ($data['driver'] === 'meta') {
            $channel->meta_phone_number_id = $data['meta_phone_number_id'] ?? null;
            $channel->meta_waba_id         = $data['meta_waba_id'] ?? null;
            if (!empty($data['meta_access_token'])) {
                $channel->meta_access_token = $data['meta_access_token'];
            }
            $channel->meta_verify_token = $data['meta_verify_token'] ?? null;
        }
    }

    /** Only one default channel per business. */
    private function applyDefault(WaChannel $channel, Request $request, int $businessId): void
    {
        $isDefault = $request->boolean('is_default');
        $channel->is_default = $isDefault;

        if ($isDefault) {
            WaChannel::where('business_id', $businessId)
                ->when($channel->exists, fn ($q) => $q->where('id', '!=', $channel->id))
                ->update(['is_default' => false]);
        }
    }
}
