<?php

namespace App\Http\Controllers;

use App\Models\ClientRequest;
use App\Models\ClientSubscription;
use App\Models\Message;
use App\Models\Payment;
use App\Models\AgencyNotification;
use App\Models\NotificationSetting;
use App\Models\Plan;
use App\Models\Service;
use App\Models\Task;
use App\Models\User;
use App\Models\SystemSetting;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Hash;
use Illuminate\Validation\Rule;
use Illuminate\View\View;

class ClientController extends Controller
{
    public function dashboard(Request $request): View
    {
        $user = $request->user();
        $subscription = $this->activeSubscription($user->id);
        $oneTimeClient = $user->client_type === 'one_time';

        return view('client.dashboard', [
            'subscription' => $subscription,
            'stats' => $oneTimeClient ? [
                'Open Orders' => ClientRequest::where('user_id', $user->id)->whereNotIn('status', ['approved', 'completed', 'delivered', 'rejected'])->count(),
                'Completed Work' => Task::where('client_id', $user->id)->whereIn('status', ['approved', 'completed', 'delivered'])->count(),
                'Pending Requests' => ClientRequest::where('user_id', $user->id)->where('status', 'pending')->count(),
                'Downloads' => Task::where('client_id', $user->id)->whereHas('files')->count(),
            ] : [
                'Active Plan' => $subscription ? 1 : 0,
                'Total Work Limit' => $subscription?->plan?->work_limit ?? 0,
                'Completed Work' => Task::where('client_id', $user->id)->whereIn('status', ['completed', 'delivered'])->count(),
                'Remaining Work' => Task::where('client_id', $user->id)->whereNotIn('status', ['completed', 'delivered'])->count(),
                'Pending Requests' => ClientRequest::where('user_id', $user->id)->where('status', 'pending')->count(),
                'Pending Payments' => Payment::where('user_id', $user->id)->where('status', 'pending')->count(),
                'Downloads' => Task::where('client_id', $user->id)->whereHas('files')->count(),
            ],
            'tasks' => Task::where('client_id', $user->id)->latest()->take(6)->get(),
        ]);
    }

    public function plan(Request $request): View
    {
        if ($request->user()->client_type === 'one_time') {
            abort(404);
        }

        return view('client.plan', [
            'subscription' => $this->activeSubscription($request->user()->id),
            'history' => ClientSubscription::with('plan')->where('user_id', $request->user()->id)->latest()->take(8)->get(),
            'pendingPayments' => Payment::with('plan')->where('user_id', $request->user()->id)->where('status', 'pending')->latest()->get(),
            'plans' => Plan::where('status', 'active')->get(),
        ]);
    }

    public function selectPlan(Request $request): RedirectResponse
    {
        $data = $request->validate(['plan_id' => ['required', 'exists:plans,id']]);
        $plan = Plan::where('status', 'active')->findOrFail($data['plan_id']);

        if ((float) $plan->price <= 0) {
            ClientRequest::create([
                'user_id' => $request->user()->id,
                'request_type' => 'custom_plan_quote',
                'title' => 'Custom plan quote request',
                'details' => 'Client requested a custom quote for '.$plan->name.'.',
                'status' => 'pending',
            ]);
            $this->notifyAdmin('new_request_submitted', 'Custom plan quote requested', $request->user()->name.' requested a custom plan quote.');

            return redirect()->route('client.requests')->with('status', 'Custom plan quote request sent to admin.');
        }

        Payment::firstOrCreate([
            'user_id' => $request->user()->id,
            'plan_id' => $plan->id,
            'status' => 'pending',
        ], [
            'amount' => $plan->price,
            'method' => 'pending_proof',
            'admin_note' => 'Plan selected by client. Waiting for payment proof.',
        ]);

        return redirect()->route('client.payments')->with('status', 'Plan selected. Please upload payment proof to activate '.$plan->name.'.');
    }

    public function requests(Request $request): View
    {
        return view('client.requests', [
            'requests' => ClientRequest::with('service')->where('user_id', $request->user()->id)->latest()->get(),
            'services' => Service::where('status', 'active')->get(),
        ]);
    }

    public function storeRequest(Request $request): RedirectResponse
    {
        if ($request->user()->client_type !== 'one_time') {
            $subscription = $this->activeSubscription($request->user()->id);
            if (! $subscription) {
                return redirect()->route('client.plan')->withErrors(['plan' => 'Please activate a plan before submitting a new request.']);
            }

            $workLimit = (int) ($subscription->plan->work_limit ?? 0);
            if ($workLimit > 0 && (int) $subscription->usage_count >= $workLimit) {
                return redirect()->route('client.plan')->withErrors(['plan' => 'Your monthly work limit is complete. Please renew or upgrade your plan.']);
            }
        }

        $data = $request->validate([
            'service_id' => ['nullable', 'exists:services,id'],
            'request_type' => ['required', 'string', 'max:80'],
            'title' => ['required', 'string', 'max:255'],
            'details' => ['nullable', 'string'],
            'deadline' => ['nullable', 'date'],
            'file_path' => ['nullable', 'file', 'mimes:'.SystemSetting::uploadExtensions(), 'max:'.SystemSetting::uploadLimitKilobytes()],
        ]);

        if ($request->hasFile('file_path')) {
            $data['file_path'] = $request->file('file_path')->store('client-requests', 'public');
        }

        $data['user_id'] = $request->user()->id;
        ClientRequest::create($data);
        $this->notifyAdmin('new_request_submitted', 'New request submitted', $request->user()->name.' submitted '.$data['title'].'.');

        return back()->with('status', 'Request submitted.');
    }

    public function work(Request $request): View
    {
        return view('client.work', ['tasks' => Task::with('files')->where('client_id', $request->user()->id)->latest()->get()]);
    }

    public function downloads(Request $request): View
    {
        return view('client.downloads', ['tasks' => Task::with('files')->where('client_id', $request->user()->id)->latest()->get()]);
    }

    public function payments(Request $request): View
    {
        return view('client.payments', [
            'payments' => Payment::with('plan')->where('user_id', $request->user()->id)->latest()->get(),
            'plans' => Plan::where('status', 'active')->get(),
            'methods' => \App\Models\PaymentMethod::where('status', 'active')->get(),
        ]);
    }

    public function storePayment(Request $request): RedirectResponse
    {
        $data = $request->validate([
            'plan_id' => ['nullable', 'exists:plans,id'],
            'amount' => ['required', 'numeric', 'min:0'],
            'method' => ['required', 'string', 'max:80', Rule::exists('payment_methods', 'name')->where('status', 'active')],
            'transaction_reference' => ['nullable', 'string', 'max:255'],
            'proof_path' => ['nullable', 'image', 'mimes:jpg,jpeg,png,webp', 'max:'.SystemSetting::uploadLimitKilobytes()],
        ]);

        if (! empty($data['plan_id'])) {
            $plan = Plan::findOrFail($data['plan_id']);
            if ((float) $plan->price > 0 && (float) $data['amount'] < (float) $plan->price) {
                return back()->withErrors(['amount' => 'Amount must be at least the selected plan price.'])->withInput();
            }
        }

        $data['user_id'] = $request->user()->id;
        if (SystemSetting::query()->value('auto_approve_payment')) {
            $data['status'] = 'approved';
        }

        if ($request->hasFile('proof_path')) {
            $data['proof_path'] = $request->file('proof_path')->store('payment-proofs', 'public');
        }

        $payment = null;
        if (! empty($data['plan_id'])) {
            $payment = Payment::where('user_id', $request->user()->id)
                ->where('plan_id', $data['plan_id'])
                ->where('status', 'pending')
                ->where(function ($query): void {
                    $query->whereNull('proof_path')->orWhere('method', 'pending_proof');
                })
                ->latest()
                ->first();
        }

        if ($payment) {
            $payment->update($data);
        } else {
            $payment = Payment::create($data);
        }

        if (($data['status'] ?? null) === 'approved') {
            $this->activateSubscriptionFromPayment($payment);
        }
        $this->notifyAdmin('new_payment_proof_uploaded', 'Payment proof uploaded', $request->user()->name.' uploaded payment proof for admin review.');

        return back()->with('status', 'Payment proof submitted for admin review.');
    }

    public function messages(Request $request): View
    {
        return view('client.messages', [
            'messages' => Message::where('sender_id', $request->user()->id)->orWhere('receiver_id', $request->user()->id)->latest()->get(),
            'admins' => User::whereIn('role', ['super_admin', 'admin'])->get(),
        ]);
    }

    public function storeMessage(Request $request): RedirectResponse
    {
        $data = $request->validate(['subject' => 'required|string|max:255', 'body' => 'required|string']);
        $data['sender_id'] = $request->user()->id;
        $data['receiver_id'] = User::whereIn('role', ['super_admin', 'admin'])->value('id');
        Message::create($data);

        return back()->with('status', 'Message sent.');
    }

    public function profile(Request $request): View
    {
        return view('client.profile', ['user' => $request->user()]);
    }

    public function updateProfile(Request $request): RedirectResponse
    {
        $data = $request->validate([
            'name' => ['required', 'string', 'max:255'],
            'phone' => ['nullable', 'string', 'max:50'],
            'password' => ['nullable', 'string', 'min:8', 'confirmed'],
        ]);

        if (! empty($data['password'])) {
            $data['password'] = Hash::make($data['password']);
        } else {
            unset($data['password']);
        }

        $request->user()->update($data);

        return back()->with('status', 'Profile updated.');
    }

    private function notifyAdmin(string $type, string $title, string $body): void
    {
        if (NotificationSetting::where('notification_type', $type)->value('dashboard_enabled') ?? true) {
            AgencyNotification::create(['title' => $title, 'body' => $body, 'audience' => 'admin', 'status' => 'unread']);
        }
    }

    private function activeSubscription(int $userId): ?ClientSubscription
    {
        ClientSubscription::where('user_id', $userId)
            ->where('status', 'active')
            ->whereNotNull('ends_at')
            ->whereDate('ends_at', '<', today())
            ->update(['status' => 'expired']);

        return ClientSubscription::with('plan')
            ->where('user_id', $userId)
            ->where('status', 'active')
            ->where(function ($query): void {
                $query->whereNull('ends_at')->orWhereDate('ends_at', '>=', today());
            })
            ->latest()
            ->first();
    }

    private function activateSubscriptionFromPayment(Payment $payment): void
    {
        if ($payment->status !== 'approved' || ! $payment->plan_id || $payment->subscription_activated_at) {
            return;
        }

        $plan = Plan::find($payment->plan_id);
        if (! $plan) {
            return;
        }

        DB::transaction(function () use ($payment, $plan): void {
            ClientSubscription::where('user_id', $payment->user_id)
                ->where('status', 'active')
                ->update(['status' => 'inactive']);

            ClientSubscription::create([
                'user_id' => $payment->user_id,
                'plan_id' => $plan->id,
                'starts_at' => today(),
                'ends_at' => today()->addDays(max((int) $plan->duration_days, 1)),
                'status' => 'active',
                'usage_count' => 0,
            ]);

            $payment->forceFill(['subscription_activated_at' => now()])->save();
        });
    }
}
