<?php

namespace Modules\VetClinic\Http\Controllers;

use App\Transaction;
use Illuminate\Http\Request;
use Illuminate\Routing\Controller;
use Illuminate\Support\Facades\Storage;
use Modules\VetClinic\Entities\VcAppointment;
use Modules\VetClinic\Entities\VcQuotationMeta;

/**
 * Vet quotation wrapper. Drapes vet metadata + owner-approval workflow over
 * the existing ERP quotation (transactions with sub_status='quotation').
 *
 * Public approval URL uses the same email-token pattern as
 * /vet-clinic/confirm-email/{token}.
 */
class VcQuotationController extends Controller
{
    use \Modules\VetClinic\Http\Controllers\Traits\LogsVcActivity;

    /** Search ERP quotations matching a customer (used by the appointment "Link" picker). */
    public function search(Request $request)
    {
        if (!auth()->user()->can('vet_clinic.view_appointments')) {
            abort(403);
        }

        $businessId = $request->session()->get('user.business_id');
        $q = trim((string) $request->q);

        $query = Transaction::where('business_id', $businessId)
            ->where('type', 'sell')
            ->where('sub_status', 'quotation');

        if ($request->filled('contact_id')) {
            $query->where('contact_id', $request->contact_id);
        }
        if ($q !== '') {
            $query->where(function ($qq) use ($q) {
                $qq->where('invoice_no', 'like', "%$q%")
                   ->orWhere('ref_no', 'like', "%$q%");
            });
        }

        $rows = $query->orderByDesc('id')->limit(20)->get([
            'id', 'invoice_no', 'ref_no', 'final_total', 'transaction_date', 'contact_id',
        ]);

        return response()->json(['data' => $rows]);
    }

    /** Quotations already linked to an appointment, with status / amounts. */
    public function appointmentList(Request $request, $appointmentId)
    {
        if (!auth()->user()->can('vet_clinic.view_appointments')) {
            abort(403);
        }

        $businessId  = $request->session()->get('user.business_id');
        $appointment = VcAppointment::where('business_id', $businessId)->findOrFail($appointmentId);

        $rows = VcQuotationMeta::with(['transaction:id,invoice_no,ref_no,final_total,sub_status,status,transaction_date'])
            ->where('business_id', $businessId)
            ->where('appointment_id', $appointment->id)
            ->orderByDesc('id')->get();

        return response()->json(['data' => $rows]);
    }

    /** Link an existing ERP quotation to an appointment (or create the meta row). */
    public function link(Request $request, $appointmentId)
    {
        if (!auth()->user()->can('vet_clinic.manage_appointments')) {
            abort(403);
        }

        $request->validate(['transaction_id' => 'required|integer']);
        $businessId  = $request->session()->get('user.business_id');
        $appointment = VcAppointment::where('business_id', $businessId)->findOrFail($appointmentId);

        $trx = Transaction::where('business_id', $businessId)
            ->where('type', 'sell')
            ->where('sub_status', 'quotation')
            ->findOrFail($request->transaction_id);

        $meta = VcQuotationMeta::firstOrNew(['transaction_id' => $trx->id]);
        $meta->fill([
            'business_id'    => $businessId,
            'appointment_id' => $appointment->id,
            'pet_id'         => $appointment->pet_id,
            'status'         => $meta->status ?: 'draft',
            'created_by'     => $meta->created_by ?: auth()->id(),
        ])->save();

        $this->vcLog('create', $meta, ['action' => 'linked_to_appointment', 'appointment_id' => $appointment->id]);

        return response()->json(['success' => true, 'meta_id' => $meta->id, 'status' => $meta->status]);
    }

    /** Unlink (does not delete the underlying ERP quotation). */
    public function unlink(Request $request, $metaId)
    {
        if (!auth()->user()->can('vet_clinic.manage_appointments')) {
            abort(403);
        }
        $businessId = $request->session()->get('user.business_id');
        $meta = VcQuotationMeta::where('business_id', $businessId)->findOrFail($metaId);

        if ($meta->is_approved) {
            return response()->json(['success' => false, 'msg' => 'Approved quotations cannot be unlinked.'], 422);
        }
        $this->vcLog('delete', $meta);
        $meta->delete();

        return response()->json(['success' => true]);
    }

    /**
     * Generate an approval token + send the owner the public approval link via
     * the existing core notification engine (uses template_for='vc_quotation_sent'
     * which auto-fires whatever channels are enabled on that template).
     */
    public function sendApproval(Request $request, $metaId)
    {
        if (!auth()->user()->can('vet_clinic.manage_appointments')) {
            abort(403);
        }

        $request->validate([
            'expires_in_days' => 'nullable|integer|min:1|max:90',
        ]);

        $businessId = $request->session()->get('user.business_id');
        $meta = VcQuotationMeta::with(['transaction', 'appointment.owner'])
            ->where('business_id', $businessId)->findOrFail($metaId);

        if (!$meta->approval_token) {
            $meta->regenerateToken();
        }

        $meta->update([
            'status'     => 'sent',
            'sent_at'    => now(),
            'expires_at' => $request->filled('expires_in_days')
                ? now()->addDays((int) $request->expires_in_days)->toDateString()
                : ($meta->expires_at ?: now()->addDays(14)->toDateString()),
        ]);

        // Stamp a token-bearing link onto the transaction so the existing core
        // {quote_url} placeholder in the new_quotation template resolves to OUR
        // approval URL, not the staff-side preview URL. Many installs use a
        // shipping_details or shipping_address-like custom field for this; here
        // we set additional_notes which is universally read by the templater.
        $approvalUrl = route('vc.quotations.public.view', $meta->approval_token);
        if ($meta->transaction) {
            $meta->transaction->additional_notes = trim(
                ($meta->transaction->additional_notes ? $meta->transaction->additional_notes . "\n\n" : '')
                . "Approve / Reject this quotation: " . $approvalUrl
            );
            $meta->transaction->save();
        }

        // Hand off to the core notification engine. We do this best-effort —
        // the link is in the transaction notes either way.
        try {
            if (class_exists(\App\Utils\NotificationUtil::class)) {
                $notif = app(\App\Utils\NotificationUtil::class);
                if (method_exists($notif, 'autoSendNotification')) {
                    $notif->autoSendNotification($businessId, 'new_quotation', $meta->transaction, $meta->transaction->contact);
                }
            }
        } catch (\Throwable $e) {
            \Log::warning('Vet quotation notification failed: ' . $e->getMessage());
        }

        $this->vcLog('update', $meta, ['action' => 'sent_for_approval']);

        return response()->json([
            'success'      => true,
            'msg'          => 'Approval link sent (and is also saved on the quotation notes).',
            'approval_url' => $approvalUrl,
            'expires_at'   => $meta->expires_at?->toDateString(),
        ]);
    }

    // ── PUBLIC — owner-facing approval flow ─────────────────────────────────

    /** Owner-facing approval page (no auth — token-gated). */
    public function publicView(Request $request, $token)
    {
        $meta = $this->resolvePublic($token);
        if (!$meta instanceof VcQuotationMeta) return $meta;

        // First view marks the row.
        if ($meta->status === 'sent' && !$meta->viewed_at) {
            $meta->update(['status' => 'viewed', 'viewed_at' => now()]);
        }

        $transaction = $meta->transaction()
            ->with(['contact:id,name,mobile,email', 'sell_lines:id,transaction_id,product_id,quantity,unit_price_inc_tax,line_discount_amount,item_tax,item_description'])
            ->first();
        $business = \App\Business::find($meta->business_id);
        $pet      = $meta->pet;

        return view('vetClinic::quotations.public', compact('meta', 'transaction', 'business', 'pet'));
    }

    /** Owner approves — captures signature + IP, locks the row. */
    public function publicApprove(Request $request, $token)
    {
        $meta = $this->resolvePublic($token);
        if (!$meta instanceof VcQuotationMeta) return $meta;

        if (!$meta->is_actionable) {
            return response()->json(['success' => false, 'msg' => 'This quotation cannot be approved (already actioned or expired).'], 422);
        }

        $request->validate([
            'png'             => 'required|string',
            'approved_by_name'=> 'required|string|max:191',
        ]);

        $payload = $request->input('png');
        if (str_contains($payload, 'base64,')) {
            $payload = explode('base64,', $payload, 2)[1];
        }
        $binary = base64_decode($payload, true);
        if ($binary === false || strlen($binary) < 200) {
            return response()->json(['success' => false, 'msg' => 'Signature image is empty or invalid.'], 422);
        }

        $dir  = "vc_quotations/{$meta->business_id}";
        $file = "sig-{$meta->id}-" . now()->timestamp . ".png";
        $path = "{$dir}/{$file}";
        Storage::disk('public')->put($path, $binary);

        $meta->update([
            'status'                   => 'approved',
            'approved_at'              => now(),
            'approved_by_name'         => $request->approved_by_name,
            'approval_ip'              => $request->ip(),
            'approval_signature_path'  => $path,
        ]);

        return response()->json([
            'success'      => true,
            'msg'          => 'Quotation approved — thank you. The clinic has been notified.',
            'approved_at'  => $meta->approved_at->toIso8601String(),
        ]);
    }

    /** Owner rejects with a reason. */
    public function publicReject(Request $request, $token)
    {
        $meta = $this->resolvePublic($token);
        if (!$meta instanceof VcQuotationMeta) return $meta;

        if (!$meta->is_actionable) {
            return response()->json(['success' => false, 'msg' => 'This quotation cannot be rejected (already actioned or expired).'], 422);
        }

        $request->validate(['reason' => 'nullable|string|max:500']);

        $meta->update([
            'status'           => 'rejected',
            'rejected_at'      => now(),
            'rejection_reason' => $request->reason,
        ]);

        return response()->json(['success' => true, 'msg' => 'Quotation rejected. The clinic has been notified.']);
    }

    /** Stamp the converted invoice id back onto the meta (called after conversion). */
    public function markConverted(Request $request, $metaId)
    {
        if (!auth()->user()->can('vet_clinic.manage_appointments')) {
            abort(403);
        }
        $request->validate(['sell_id' => 'required|integer']);
        $businessId = $request->session()->get('user.business_id');
        $meta = VcQuotationMeta::where('business_id', $businessId)->findOrFail($metaId);
        $meta->update(['converted_sell_id' => (int) $request->sell_id]);
        $this->vcLog('update', $meta, ['action' => 'converted_to_invoice', 'sell_id' => $request->sell_id]);
        return response()->json(['success' => true]);
    }

    /**
     * Resolve & validate a public token; returns a meta or a 404 response.
     */
    private function resolvePublic($token)
    {
        if (!is_string($token) || !preg_match('/^[a-f0-9]{32,64}$/i', $token)) {
            abort(404);
        }
        $meta = VcQuotationMeta::where('approval_token', strtolower($token))->first();
        if (!$meta) abort(404);

        // Auto-expire if past its date.
        if ($meta->expires_at && $meta->expires_at->isPast() && in_array($meta->status, ['sent', 'viewed'], true)) {
            $meta->update(['status' => 'expired']);
        }

        return $meta;
    }
}
