<?php

namespace Modules\VetClinic\Http\Controllers;

use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Validator;
use Illuminate\Support\Str;
use Illuminate\Validation\Rule;
use Modules\PortalApi\Entities\PortalBrand;
use Modules\PortalApi\Services\PwaBuilder;

/**
 * Clinic-admin UI for the pet-owner PWA's per-clinic branding.
 *
 * Editor of a portal_brands row scoped to the current business. Lets the
 * admin pick a slug (the URL the PWA opens at: /app/{slug}/), customize
 * name + accent color + logo, set contact details, and toggle which
 * sign-in methods owners can use.
 */
class VcPortalBrandController extends Controller
{
    public function index(Request $request)
    {
        $businessId = $this->businessId($request);
        if (! $businessId) {
            abort(403, 'No business in session.');
        }

        $brand   = PortalBrand::where('business_id', $businessId)->first();
        $appUrl  = url('/app/' . ($brand?->slug ?? '')) . '/';

        return view('vetClinic::settings.portal_brand', compact('brand', 'appUrl'));
    }

    public function save(Request $request)
    {
        $businessId = $this->businessId($request);
        if (! $businessId) {
            abort(403);
        }

        // The current business's own row is allowed to keep its slug/domain
        // on edit — everyone else must be globally unique. Laravel's string
        // unique syntax can't express "!=", so we use the Rule builder.
        $brandId = PortalBrand::where('business_id', $businessId)->value('id');

        $data = $this->validate($request, [
            'slug'            => ['required', 'string', 'min:2', 'max:64', 'regex:/^[a-z0-9][a-z0-9-]*$/',
                                  Rule::unique('portal_brands', 'slug')->ignore($brandId)],
            'name'            => 'required|string|max:191',
            'accent_hex'      => 'required|string|regex:/^#?[0-9A-Fa-f]{6}$/',
            'custom_domain'   => ['nullable', 'string', 'max:191',
                                  'regex:/^[a-z0-9.-]+\.[a-z]{2,}$/i',
                                  Rule::unique('portal_brands', 'custom_domain')->ignore($brandId)],
            'contact_phone'   => 'nullable|string|max:32',
            'contact_email'   => 'nullable|email|max:191',
            'address'         => 'nullable|string|max:191',
            'login_methods'   => 'nullable|array',
            'login_methods.*' => 'in:otp,magic,password,staff',
            'is_active'       => 'nullable|boolean',
            'public_booking'  => 'nullable|boolean',
            'booking_otp'     => 'nullable|boolean',
        ]);

        if ($data['accent_hex'][0] !== '#') {
            $data['accent_hex'] = '#' . $data['accent_hex'];
        }

        $data['business_id']   = $businessId;
        $data['slug']          = strtolower($data['slug']);
        $data['custom_domain'] = isset($data['custom_domain']) ? strtolower($data['custom_domain']) : null;
        $data['login_methods'] = $data['login_methods'] ?: ['otp','magic','password','staff'];
        $data['is_active']      = filter_var($request->input('is_active', true), FILTER_VALIDATE_BOOLEAN);
        $data['public_booking'] = filter_var($request->input('public_booking', false), FILTER_VALIDATE_BOOLEAN);
        $data['booking_otp']    = filter_var($request->input('booking_otp', false), FILTER_VALIDATE_BOOLEAN);

        PortalBrand::updateOrCreate(['business_id' => $businessId], $data);

        return redirect()->route('vc.portal-brand.index')
            ->with('status', 'Portal brand saved.');
    }

    /**
     * Logo upload endpoint. Accepts a single image file (png/jpg/svg/webp),
     * saves it under public/uploads/portal-brands/{business_id}/logo.{ext},
     * and updates the brand's logo_url.
     */
    public function uploadLogo(Request $request)
    {
        $businessId = $this->businessId($request);
        if (! $businessId) {
            abort(403);
        }

        $this->validate($request, [
            'logo' => 'required|file|image|mimes:png,jpg,jpeg,svg,webp|max:1024', // 1 MB
        ]);

        $brand = PortalBrand::where('business_id', $businessId)->first();
        if (! $brand) {
            return back()->with('error', 'Save the brand basics first, then upload the logo.');
        }

        $file = $request->file('logo');
        $ext  = strtolower($file->getClientOriginalExtension() ?: $file->extension());

        $relDir = 'uploads/portal-brands/' . $businessId;
        $absDir = public_path($relDir);
        if (! is_dir($absDir)) {
            @mkdir($absDir, 0775, true);
        }

        $filename = 'logo-' . Str::random(6) . '.' . $ext;
        $file->move($absDir, $filename);

        $brand->logo_url = url($relDir . '/' . $filename);
        $brand->save();

        return back()->with('status', 'Logo uploaded.');
    }

    /**
     * Rebuild the pet-owner PWA (pwa-owner/ → public/app) on demand.
     *
     * This is the supported, mistake-proof way to redeploy the app: it always
     * builds the committed source to the served directory (safe temp-then-swap),
     * so the "reverted to old version" problem (building a stale copy, or vite's
     * relative outDir writing to the wrong public/app) can't recur.
     */
    public function rebuildPwa(Request $request)
    {
        if (! $this->businessId($request)) {
            abort(403);
        }

        // Serialize builds — a second click while one runs would fight over
        // public/app. 10-minute lock window matches the build timeout.
        $lock = Cache::lock('portal_pwa_build', 600);
        if (! $lock->get()) {
            return response()->json([
                'ok'  => false,
                'msg' => 'A rebuild is already running. Give it a few seconds and try again.',
            ], 429);
        }

        try {
            $result = PwaBuilder::build();
        } finally {
            $lock->release();
        }

        return response()->json([
            'ok'       => $result['ok'],
            'msg'      => $result['ok']
                            ? 'Pet portal app rebuilt successfully' . (isset($result['duration']) ? " in {$result['duration']}s." : '.')
                            : ($result['hint'] ?? 'Build failed.'),
            'output'   => $result['output'] ?? '',
            'duration' => $result['duration'] ?? null,
        ], $result['ok'] ? 200 : 500);
    }

    private function businessId(Request $request): ?int
    {
        // Stay consistent with the rest of the VetClinic module.
        return session('user.business_id') ?? auth()->user()?->business_id ?? null;
    }
}
