<?php

namespace App\Http\Controllers\Api;

use App\Http\Controllers\Controller;
use App\Models\BusinessTrip;
use App\Models\Location;
use App\Services\BusinessTripService;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;

class BusinessTripController extends Controller
{
    public function __construct(
        private BusinessTripService $businessTripService
    ) {}

    /**
     * Daftar perjalanan dinas user
     */
    public function index(Request $request): JsonResponse
    {
        $request->validate([
            'status' => 'nullable|in:pending,approved,rejected,ongoing,completed,cancelled',
        ]);

        $query = BusinessTrip::where('user_id', $request->user()->id)
            ->with(['approver'])
            ->orderByDesc('start_date');

        if ($request->status) {
            $query->where('status', $request->status);
        }

        $trips = $query->paginate(15);

        return response()->json([
            'success' => true,
            'data' => $trips,
        ]);
    }

    /**
     * Membuat pengajuan perjalanan dinas baru
     */
    public function store(Request $request): JsonResponse
    {
        $request->validate([
            'title' => 'required|string|max:255',
            'description' => 'nullable|string',
            'destination_city' => 'required|string|max:255',
            'destination_province' => 'nullable|string|max:255',
            'destination_address' => 'nullable|string',
            'destination_latitude' => 'nullable|numeric|between:-90,90',
            'destination_longitude' => 'nullable|numeric|between:-180,180',
            'start_date' => 'required|date|after_or_equal:today',
            'end_date' => 'required|date|after_or_equal:start_date',
        ]);

        $result = $this->businessTripService->create($request->user(), $request->all());

        return response()->json($result, $result['success'] ? 201 : 400);
    }

    /**
     * Detail perjalanan dinas
     */
    public function show(Request $request, BusinessTrip $businessTrip): JsonResponse
    {
        // Pastikan user hanya bisa lihat trip miliknya atau jika dia manager/admin
        $user = $request->user();
        if ($businessTrip->user_id !== $user->id && !$user->isManager() && !$user->isAdmin()) {
            return response()->json([
                'success' => false,
                'message' => 'Tidak diizinkan mengakses data ini',
            ], 403);
        }

        return response()->json([
            'success' => true,
            'data' => $businessTrip->load(['user', 'approver', 'attendances.referenceOffice']),
        ]);
    }

    /**
     * Cancel perjalanan dinas
     */
    public function cancel(Request $request, BusinessTrip $businessTrip): JsonResponse
    {
        if ($businessTrip->user_id !== $request->user()->id) {
            return response()->json([
                'success' => false,
                'message' => 'Tidak diizinkan membatalkan perjalanan dinas ini',
            ], 403);
        }

        if (!in_array($businessTrip->status, ['pending', 'approved'])) {
            return response()->json([
                'success' => false,
                'message' => 'Perjalanan dinas tidak dapat dibatalkan',
            ], 400);
        }

        $businessTrip->update(['status' => 'cancelled']);

        return response()->json([
            'success' => true,
            'message' => 'Perjalanan dinas berhasil dibatalkan',
            'data' => $businessTrip->fresh(),
        ]);
    }

    /**
     * Approve perjalanan dinas (untuk manager/admin)
     */
    public function approve(Request $request, BusinessTrip $businessTrip): JsonResponse
    {
        $user = $request->user();

        if (!$user->isManager() && !$user->isAdmin()) {
            return response()->json([
                'success' => false,
                'message' => 'Hanya manager atau admin yang dapat menyetujui perjalanan dinas',
            ], 403);
        }

        $result = $this->businessTripService->approve($businessTrip, $user);

        return response()->json($result, $result['success'] ? 200 : 400);
    }

    /**
     * Reject perjalanan dinas (untuk manager/admin)
     */
    public function reject(Request $request, BusinessTrip $businessTrip): JsonResponse
    {
        $request->validate([
            'reason' => 'required|string',
        ]);

        $user = $request->user();

        if (!$user->isManager() && !$user->isAdmin()) {
            return response()->json([
                'success' => false,
                'message' => 'Hanya manager atau admin yang dapat menolak perjalanan dinas',
            ], 403);
        }

        $result = $this->businessTripService->reject($businessTrip, $user, $request->reason);

        return response()->json($result, $result['success'] ? 200 : 400);
    }

    /**
     * Check in perjalanan dinas
     */
    public function checkIn(Request $request, BusinessTrip $businessTrip): JsonResponse
    {
        if ($businessTrip->user_id !== $request->user()->id) {
            return response()->json([
                'success' => false,
                'message' => 'Tidak diizinkan melakukan check-in untuk perjalanan dinas ini',
            ], 403);
        }

        $request->validate([
            'latitude' => 'required|numeric|between:-90,90',
            'longitude' => 'required|numeric|between:-180,180',
            'address' => 'nullable|string',
            'city' => 'nullable|string',
            'notes' => 'nullable|string',
        ]);

        $result = $this->businessTripService->checkIn(
            trip: $businessTrip,
            latitude: $request->latitude,
            longitude: $request->longitude,
            address: $request->address,
            city: $request->city,
            notes: $request->notes
        );

        return response()->json($result, $result['success'] ? 200 : 400);
    }

    /**
     * Check out perjalanan dinas
     */
    public function checkOut(Request $request, BusinessTrip $businessTrip): JsonResponse
    {
        if ($businessTrip->user_id !== $request->user()->id) {
            return response()->json([
                'success' => false,
                'message' => 'Tidak diizinkan melakukan check-out untuk perjalanan dinas ini',
            ], 403);
        }

        $request->validate([
            'latitude' => 'required|numeric|between:-90,90',
            'longitude' => 'required|numeric|between:-180,180',
            'address' => 'nullable|string',
            'city' => 'nullable|string',
            'notes' => 'nullable|string',
        ]);

        $result = $this->businessTripService->checkOut(
            trip: $businessTrip,
            latitude: $request->latitude,
            longitude: $request->longitude,
            address: $request->address,
            city: $request->city,
            notes: $request->notes
        );

        return response()->json($result, $result['success'] ? 200 : 400);
    }

    /**
     * Status presensi hari ini untuk perjalanan dinas
     */
    public function todayStatus(Request $request, BusinessTrip $businessTrip): JsonResponse
    {
        if ($businessTrip->user_id !== $request->user()->id) {
            return response()->json([
                'success' => false,
                'message' => 'Tidak diizinkan mengakses data ini',
            ], 403);
        }

        $status = $this->businessTripService->getTodayStatus($businessTrip);

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

    /**
     * Mendapatkan lokasi rekomendasi untuk presensi dinas
     */
    public function recommendedLocations(Request $request, BusinessTrip $businessTrip): JsonResponse
    {
        $locations = $this->businessTripService->getRecommendedLocations($businessTrip);

        return response()->json([
            'success' => true,
            'data' => $locations,
        ]);
    }

    /**
     * Perjalanan dinas aktif (ongoing) milik user
     */
    public function active(Request $request): JsonResponse
    {
        $trip = BusinessTrip::where('user_id', $request->user()->id)
            ->whereIn('status', ['approved', 'ongoing'])
            ->where('start_date', '<=', now())
            ->where('end_date', '>=', now())
            ->with(['attendances.referenceOffice'])
            ->first();

        return response()->json([
            'success' => true,
            'data' => $trip,
        ]);
    }

    /**
     * Daftar perjalanan dinas pending untuk approval (manager/admin)
     */
    public function pendingApprovals(Request $request): JsonResponse
    {
        $user = $request->user();

        if (!$user->isManager() && !$user->isAdmin()) {
            return response()->json([
                'success' => false,
                'message' => 'Hanya manager atau admin yang dapat mengakses',
            ], 403);
        }

        $trips = BusinessTrip::where('company_id', $user->company_id)
            ->where('status', 'pending')
            // Hide super_admin from pending approvals (using Spatie roles)
            ->whereHas('user', function ($q) {
                $q->whereDoesntHave('roles', function ($r) {
                    $r->where('name', 'super_admin');
                });
            })
            ->with('user')
            ->orderBy('start_date')
            ->paginate(15);

        return response()->json([
            'success' => true,
            'data' => $trips,
        ]);
    }

    /**
     * Mendapatkan lokasi dinas terdekat berdasarkan koordinat user
     * Digunakan untuk absen perjalanan dinas tanpa pengajuan
     * Menggunakan tabel locations (unified) dengan filter allow_business_trip=true
     * Exclude: BPKP Pusat (kantor utama, bukan tujuan dinas)
     */
    public function nearbyLocations(Request $request): JsonResponse
    {
        $request->validate([
            'latitude' => 'required|numeric|between:-90,90',
            'longitude' => 'required|numeric|between:-180,180',
            'limit' => 'nullable|integer|min:1|max:20',
        ]);

        $user = $request->user();
        $limit = $request->get('limit', 5);

        // Use unified Location model with allow_business_trip filter
        $locations = Location::getNearbyLocations(
            companyId: $user->company_id,
            latitude: $request->latitude,
            longitude: $request->longitude,
            limit: $limit + 1, // Ambil 1 lebih untuk antisipasi filter
            allowBusinessTrip: true
        );

        // Exclude BPKP Pusat dan limit hasil
        $locations = $locations->filter(fn($loc) => $loc->name !== 'BPKP Pusat')->take($limit);

        // Format response dengan jarak dalam meter
        // Sort: primary first, then by distance
        $data = $locations->map(function ($location) {
            return [
                'id' => $location->id,
                'name' => $location->name,
                'code' => $location->code,
                'type' => $location->type,
                'type_label' => $location->getTypeLabel(),
                'city' => $location->city,
                'province' => $location->province,
                'address' => $location->address,
                'latitude' => $location->latitude,
                'longitude' => $location->longitude,
                'radius' => $location->radius,
                'distance' => round($location->distance), // dalam meter
                'distance_text' => $location->distance < 1000
                    ? round($location->distance) . ' m'
                    : round($location->distance / 1000, 1) . ' km',
                'is_within_radius' => $location->distance <= $location->radius,
                'is_primary' => $location->is_primary ?? false,
            ];
        })->sortBy([
            ['is_primary', 'desc'], // Primary locations first
            ['distance', 'asc'],    // Then by distance
        ])->values();

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

    /**
     * Mendapatkan semua lokasi dinas aktif untuk company user
     * Primary locations tampil di urutan atas
     * Menggunakan tabel locations (unified) dengan filter allow_business_trip=true
     * Exclude: BPKP Pusat (kantor utama, bukan tujuan dinas)
     */
    public function allLocations(Request $request): JsonResponse
    {
        $user = $request->user();

        // Use unified Location model with allow_business_trip filter
        // Exclude BPKP Pusat dari pilihan dinas
        $locations = Location::active()
            ->forCompany($user->company_id)
            ->where('allow_business_trip', true)
            ->where('name', '!=', 'BPKP Pusat')
            ->ordered() // Primary first, then by sort_order, then by name
            ->get()
            ->map(function ($location) {
                return [
                    'id' => $location->id,
                    'name' => $location->name,
                    'code' => $location->code,
                    'type' => $location->type,
                    'type_label' => $location->getTypeLabel(),
                    'city' => $location->city,
                    'province' => $location->province,
                    'address' => $location->address,
                    'latitude' => $location->latitude,
                    'longitude' => $location->longitude,
                    'radius' => $location->radius,
                    'is_primary' => $location->is_primary ?? false,
                ];
            });

        return response()->json([
            'success' => true,
            'data' => $locations,
        ]);
    }

    /**
     * Check-in langsung ke lokasi dinas (tanpa pengajuan)
     * Untuk mode allow_business_trip = true tapi tanpa proses approval
     * Mendukung 2 mode:
     * 1. Dengan location_id: checkin ke lokasi terdaftar (validasi radius)
     * 2. Dengan custom_location=true: checkin ke lokasi manual (tanpa validasi radius)
     */
    public function directCheckIn(Request $request): JsonResponse
    {
        $user = $request->user();
        $company = $user->company;
        $locationEditable = $company->allow_editable_location ?? true;

        // Jika custom_location=true dan location_editable, tidak perlu location_id
        if ($request->boolean('custom_location') && $locationEditable) {
            $request->validate([
                'latitude' => 'required|numeric|between:-90,90',
                'longitude' => 'required|numeric|between:-180,180',
                'address' => 'nullable|string',
                'notes' => 'nullable|string',
            ]);

            // Buat attendance dengan lokasi custom (tanpa location terdaftar)
            $result = $this->businessTripService->directCheckInCustom(
                user: $user,
                latitude: $request->latitude,
                longitude: $request->longitude,
                address: $request->address,
                notes: $request->notes
            );

            return response()->json($result, $result['success'] ? 200 : 400);
        }

        // Mode standar: dengan location_id terdaftar
        // Use unified Location table
        $request->validate([
            'location_id' => 'required|exists:locations,id',
            'latitude' => 'required|numeric|between:-90,90',
            'longitude' => 'required|numeric|between:-180,180',
            'address' => 'nullable|string',
            'notes' => 'nullable|string',
        ]);

        $location = Location::findOrFail($request->location_id);

        // Validasi lokasi milik company yang sama
        if ($location->company_id !== $user->company_id) {
            return response()->json([
                'success' => false,
                'message' => 'Lokasi tidak valid untuk perusahaan Anda',
            ], 400);
        }

        // Validasi lokasi support business trip
        if (!$location->allow_business_trip) {
            return response()->json([
                'success' => false,
                'message' => 'Lokasi ini tidak tersedia untuk perjalanan dinas',
            ], 400);
        }

        // Validasi user berada dalam radius lokasi
        // KECUALI jika location_editable=true
        if (!$locationEditable && !$location->isWithinRadius($request->latitude, $request->longitude)) {
            $distance = $location->distanceFrom($request->latitude, $request->longitude);
            return response()->json([
                'success' => false,
                'message' => 'Anda berada di luar radius lokasi (' . round($distance) . 'm dari lokasi, radius: ' . $location->radius . 'm)',
                'data' => [
                    'distance' => round($distance),
                    'radius' => $location->radius,
                ],
            ], 400);
        }

        // Buat attendance langsung dengan tipe business_trip
        $result = $this->businessTripService->directCheckIn(
            user: $user,
            location: $location,
            latitude: $request->latitude,
            longitude: $request->longitude,
            address: $request->address,
            notes: $request->notes
        );

        return response()->json($result, $result['success'] ? 200 : 400);
    }

    /**
     * Check-out langsung dari lokasi dinas (tanpa pengajuan)
     */
    public function directCheckOut(Request $request): JsonResponse
    {
        $request->validate([
            'latitude' => 'required|numeric|between:-90,90',
            'longitude' => 'required|numeric|between:-180,180',
            'address' => 'nullable|string',
            'notes' => 'nullable|string',
        ]);

        $result = $this->businessTripService->directCheckOut(
            user: $request->user(),
            latitude: $request->latitude,
            longitude: $request->longitude,
            address: $request->address,
            notes: $request->notes
        );

        return response()->json($result, $result['success'] ? 200 : 400);
    }
}
