<?php

namespace App\Http\Controllers\Api\V1;

use App\Http\Controllers\Api\V1\Concerns\RespondsWithApi;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;

class ProfessionalController extends Controller
{
    use RespondsWithApi;

    public function apply(Request $request)
    {
        $data = $request->validate([
            'name' => ['required', 'string', 'max:120'],
            'phone' => ['required', 'string', 'max:32'],
            'gender' => ['nullable', 'string', 'max:32'],
            'city_id' => ['nullable', 'integer'],
            'referral_code' => ['nullable', 'string', 'max:60'],
        ]);

        $applicationId = DB::table('professional_applications')->insertGetId([
            'name' => $data['name'],
            'phone' => $data['phone'],
            'gender' => $data['gender'] ?? null,
            'city_id' => $data['city_id'] ?? null,
            'source' => $data['referral_code'] ? 'buddy' : 'app',
            'referral_code' => $data['referral_code'] ?? null,
            'status' => 'lead',
            'created_at' => now(),
            'updated_at' => now(),
        ]);

        if (! empty($data['referral_code'])) {
            $code = DB::table('referral_codes')->where('code', strtoupper($data['referral_code']))->where('status', 'active')->first();
            if ($code) {
                DB::table('referral_leads')->insert([
                    'referral_code_id' => $code->id,
                    'referred_phone' => $data['phone'],
                    'professional_application_id' => $applicationId,
                    'status' => 'lead_created',
                    'expires_at' => now()->addDays(45),
                    'created_at' => now(),
                    'updated_at' => now(),
                ]);
            }
        }

        return $this->ok(DB::table('professional_applications')->where('id', $applicationId)->first(), 'Professional application submitted.', [], 201);
    }

    public function profile(Request $request)
    {
        return $this->ok($this->currentProfessional($request));
    }

    public function onboardingStatus(Request $request)
    {
        $pro = $this->currentProfessional($request);

        return $this->ok([
            'professional' => $pro,
            'documents' => DB::table('professional_documents')->where('professional_id', $pro->id)->get(),
            'skills' => DB::table('professional_skills')->where('professional_id', $pro->id)->get(),
        ]);
    }

    public function documents(Request $request)
    {
        $data = $request->validate([
            'document_type' => ['required', 'string', 'max:60'],
            'document_number' => ['nullable', 'string', 'max:120'],
            'file_path' => ['nullable', 'string', 'max:255'],
        ]);

        $pro = $this->currentProfessional($request);

        $id = DB::table('professional_documents')->insertGetId([
            'professional_id' => $pro->id,
            'document_type' => $data['document_type'],
            'document_number_encrypted' => isset($data['document_number']) ? encrypt($data['document_number']) : null,
            'file_path' => $data['file_path'] ?? null,
            'verification_status' => 'pending',
            'created_at' => now(),
            'updated_at' => now(),
        ]);

        return $this->ok(DB::table('professional_documents')->where('id', $id)->first(), 'Document uploaded.', [], 201);
    }

    public function availability(Request $request)
    {
        $data = $request->validate([
            'day_of_week' => ['required', 'integer', 'min:0', 'max:6'],
            'start_time' => ['required', 'date_format:H:i'],
            'end_time' => ['required', 'date_format:H:i'],
        ]);

        $pro = $this->currentProfessional($request);

        $id = DB::table('professional_availabilities')->insertGetId([
            'professional_id' => $pro->id,
            'day_of_week' => $data['day_of_week'],
            'start_time' => $data['start_time'],
            'end_time' => $data['end_time'],
            'status' => 'active',
            'created_at' => now(),
            'updated_at' => now(),
        ]);

        return $this->ok(DB::table('professional_availabilities')->where('id', $id)->first(), 'Availability saved.', [], 201);
    }

    public function location(Request $request)
    {
        $data = $request->validate([
            'lat' => ['required', 'numeric'],
            'lng' => ['required', 'numeric'],
            'accuracy' => ['nullable', 'numeric'],
        ]);

        $pro = $this->currentProfessional($request);

        DB::table('professional_locations')->insert([
            'professional_id' => $pro->id,
            'lat' => $data['lat'],
            'lng' => $data['lng'],
            'accuracy' => $data['accuracy'] ?? null,
            'captured_at' => now(),
            'created_at' => now(),
            'updated_at' => now(),
        ]);

        return $this->ok([], 'Location updated.');
    }

    public function jobOffers(Request $request)
    {
        $pro = $this->currentProfessional($request);

        return $this->ok(DB::table('assignment_offers')->where('professional_id', $pro->id)->where('status', 'offered')->latest('id')->get());
    }

    public function acceptOffer(Request $request, int $offer)
    {
        $pro = $this->currentProfessional($request);
        $row = DB::table('assignment_offers')->where('id', $offer)->where('professional_id', $pro->id)->first();

        if (! $row) {
            return $this->fail('OFFER_NOT_FOUND', 'Offer not found.', [], 404);
        }

        DB::transaction(function () use ($row, $pro) {
            DB::table('assignment_offers')->where('id', $row->id)->update([
                'status' => 'accepted',
                'responded_at' => now(),
                'updated_at' => now(),
            ]);

            DB::table('booking_assignments')->insert([
                'booking_id' => $row->booking_id,
                'professional_id' => $pro->id,
                'assigned_by_type' => 'professional',
                'assigned_by_id' => $pro->id,
                'assignment_type' => 'offer_accept',
                'status' => 'accepted',
                'assigned_at' => now(),
                'accepted_at' => now(),
                'created_at' => now(),
                'updated_at' => now(),
            ]);

            DB::table('bookings')->where('id', $row->booking_id)->update([
                'assignment_status' => 'assigned',
                'status' => 'assigned',
                'updated_at' => now(),
            ]);
        });

        return $this->ok([], 'Offer accepted.');
    }

    public function rejectOffer(Request $request, int $offer)
    {
        $pro = $this->currentProfessional($request);
        DB::table('assignment_offers')->where('id', $offer)->where('professional_id', $pro->id)->update([
            'status' => 'rejected',
            'responded_at' => now(),
            'updated_at' => now(),
        ]);

        return $this->ok([], 'Offer rejected.');
    }

    public function bookings(Request $request)
    {
        $pro = $this->currentProfessional($request);

        return $this->ok(DB::table('booking_assignments')
            ->join('bookings', 'bookings.id', '=', 'booking_assignments.booking_id')
            ->where('booking_assignments.professional_id', $pro->id)
            ->select('bookings.*', 'booking_assignments.status as assignment_status_current')
            ->latest('bookings.id')
            ->paginate(20));
    }

    public function updateBookingStatus(Request $request, int $booking, string $status)
    {
        $allowed = ['en-route' => 'en_route', 'arrived' => 'arrived', 'start' => 'started', 'complete' => 'completed'];

        if (! isset($allowed[$status])) {
            return $this->fail('INVALID_STATUS', 'Invalid Pro booking status.', [], 422);
        }

        $pro = $this->currentProfessional($request);
        $assignment = DB::table('booking_assignments')->where('booking_id', $booking)->where('professional_id', $pro->id)->latest('id')->first();

        if (! $assignment) {
            return $this->fail('ASSIGNMENT_NOT_FOUND', 'Booking assignment not found.', [], 404);
        }

        $assignmentStatus = $allowed[$status];
        $timeColumn = $assignmentStatus === 'en_route' ? null : $assignmentStatus . '_at';

        $update = ['status' => $assignmentStatus, 'updated_at' => now()];
        if ($timeColumn && in_array($timeColumn, ['arrived_at', 'started_at', 'completed_at'], true)) {
            $update[$timeColumn] = now();
        }

        DB::table('booking_assignments')->where('id', $assignment->id)->update($update);
        DB::table('bookings')->where('id', $booking)->update([
            'status' => $assignmentStatus === 'completed' ? 'completed' : $assignmentStatus,
            'assignment_status' => $assignmentStatus === 'completed' ? 'completed' : 'assigned',
            'completed_at' => $assignmentStatus === 'completed' ? now() : null,
            'updated_at' => now(),
        ]);

        if ($assignmentStatus === 'completed') {
            DB::table('professional_earnings')->insert([
                'professional_id' => $pro->id,
                'booking_id' => $booking,
                'earning_type' => 'service_fee',
                'amount' => 150,
                'status' => 'payable',
                'created_at' => now(),
                'updated_at' => now(),
            ]);
        }

        return $this->ok(DB::table('booking_assignments')->where('id', $assignment->id)->first(), 'Booking status updated.');
    }

    public function earnings(Request $request)
    {
        $pro = $this->currentProfessional($request);

        return $this->ok([
            'summary' => [
                'pending' => DB::table('professional_earnings')->where('professional_id', $pro->id)->where('status', 'pending')->sum('amount'),
                'payable' => DB::table('professional_earnings')->where('professional_id', $pro->id)->where('status', 'payable')->sum('amount'),
                'paid' => DB::table('professional_earnings')->where('professional_id', $pro->id)->where('status', 'paid')->sum('amount'),
            ],
            'items' => DB::table('professional_earnings')->where('professional_id', $pro->id)->latest('id')->paginate(20),
        ]);
    }

    private function currentProfessional(Request $request): object
    {
        $pro = DB::table('professionals')->where('user_id', $request->user()->id)->first();

        if ($pro) {
            return $pro;
        }

        $id = DB::table('professionals')->insertGetId([
            'user_id' => $request->user()->id,
            'pro_code' => 'PRO-' . strtoupper(Str::random(6)),
            'onboarding_status' => 'lead',
            'employment_type' => 'partner',
            'status' => 'lead',
            'created_at' => now(),
            'updated_at' => now(),
        ]);

        return DB::table('professionals')->where('id', $id)->first();
    }
}
