<?php

namespace App\Http\Controllers\Api\Pos;

use App\Http\Controllers\Controller;
use App\Models\User;
use App\Models\Address;
use App\Models\Country;
use App\Models\State;
use App\Models\City;
use Illuminate\Database\QueryException;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Validator;
use Illuminate\Validation\Rule;

class CustomerController extends Controller
{
    /**
     * Get or create walk-in customer
     */
    public function getWalkInCustomer(): JsonResponse
    {
        try {
            // Keep this endpoint independent from roles relation queries.
            // It only needs a deterministic walk-in customer record.
            $walkInCustomer = User::firstOrCreate(
                ['mobile' => '9999999999'],
                [
                    'name' => 'Walk In Customer',
                    'email' => null,
                    'customer_type' => 'retail',
                    'password' => Hash::make('password'),
                ]
            );

            if ($walkInCustomer->name !== 'Walk In Customer' || empty($walkInCustomer->customer_type)) {
                $walkInCustomer->update([
                    'name' => 'Walk In Customer',
                    'customer_type' => $walkInCustomer->customer_type ?: 'retail',
                ]);
            }

            return response()->json([
                'success' => true,
                'data' => [
                    'id' => $walkInCustomer->id,
                    'name' => $walkInCustomer->name,
                    'mobile' => $walkInCustomer->mobile,
                    'email' => $walkInCustomer->email,
                    'customer_type' => $walkInCustomer->customer_type ?? 'retail',
                ],
            ]);
        } catch (\Throwable $e) {
            Log::error('POS walk-in customer fetch failed', [
                'error' => $e->getMessage(),
                'file' => $e->getFile(),
                'line' => $e->getLine(),
            ]);

            return response()->json([
                'success' => false,
                'message' => 'Unable to load walk-in customer.',
            ], 500);
        }
    }

    /**
     * Search customer by mobile number (supports partial match)
     */
    public function search(Request $request): JsonResponse
    {
        $mobile = $request->get('mobile', '');

        if (strlen($mobile) < 4) {
            return response()->json([
                'success' => true,
                'data' => [],
            ]);
        }

        $customers = User::where('mobile', 'like', "%{$mobile}%")
            ->whereDoesntHave('roles', function ($query) {
                $query->whereIn('name', ['admin', 'staff']);
            })
            ->limit(10)
            ->get()
            ->map(function ($customer) {
                return [
                    'id' => $customer->id,
                    'name' => $customer->name,
                    'mobile' => $customer->mobile,
                    'email' => $customer->email,
                    'customer_type' => $customer->customer_type ?? 'retail',
                ];
            });

        return response()->json([
            'success' => true,
            'data' => $customers,
        ]);
    }

    /**
     * Create new customer
     */
    public function store(Request $request): JsonResponse
    {
        // Log all request data for debugging
        Log::info('POS Customer Create Request', [
            'all' => $request->all(),
            'json' => $request->json()->all(),
            'customer_type_input' => $request->input('customer_type'),
            'customer_type_get' => $request->get('customer_type'),
            'customer_type_json' => $request->json('customer_type'),
            'content_type' => $request->header('Content-Type'),
        ]);

        // Normalize mobile (strip +91 prefix) before validation
        $normalizedMobile = preg_replace('/^\+91/', '', trim($request->input('mobile', '')));
        
        // Check if mobile already exists in database (check ALL users first)
        $existingUser = User::where('mobile', $normalizedMobile)->first();
        
        if ($existingUser) {
            // Check if existing user is a customer (not admin/staff)
            $isCustomer = !$existingUser->isAdmin() && !$existingUser->isStaff();
            
            if ($isCustomer) {
                return response()->json([
                    'success' => false,
                    'message' => 'Customer with this mobile number already exists. Please select the existing customer instead of creating a new one.',
                    'errors' => [
                        'mobile' => ['Customer with this mobile number already exists. Please select the existing customer instead of creating a new one.']
                    ],
                ], 422);
            }
        }
        
        // Merge normalized mobile back into request for validation
        $request->merge(['mobile' => $normalizedMobile]);
        
        $validator = Validator::make($request->all(), [
            'name' => 'required|string|max:255',
            'mobile' => [
                'required', 
                'string', 
                'regex:/^[6-9]\d{9}$/',
            ],
            'email' => 'nullable|email|max:255|unique:users,email',
            'gst_number' => [
                'nullable',
                'string',
                'max:15',
                'regex:/^[0-9A-Z]{15}$/',
            ],
            'customer_type' => 'nullable|in:retail,wholesale',
        ]);

        if ($validator->fails()) {
            return response()->json([
                'success' => false,
                'message' => 'Validation failed',
                'errors' => $validator->errors(),
            ], 422);
        }

        // Use normalized mobile (10 digits only) for storage
        $mobile = $normalizedMobile;

        // Get customer_type from request
        // Try multiple methods to get the value from JSON request
        $customerType = null;
        
        // Method 1: Direct from all() - Laravel merges JSON into this
        if (isset($request->all()['customer_type'])) {
            $customerType = $request->all()['customer_type'];
        }
        // Method 2: Using input()
        elseif ($request->has('customer_type')) {
            $customerType = $request->input('customer_type');
        }
        // Method 3: From JSON body directly
        elseif ($request->isJson() && $request->json()->has('customer_type')) {
            $customerType = $request->json('customer_type');
        }
        
        // Default to retail if not found or invalid
        if (empty($customerType) || !in_array($customerType, ['retail', 'wholesale'])) {
            $customerType = 'retail';
        }

        Log::info('POS Customer Create - Final customer_type', [
            'customer_type' => $customerType,
            'request_all' => $request->all(),
            'request_input' => $request->input('customer_type'),
            'is_json' => $request->isJson(),
            'json_all' => $request->isJson() ? $request->json()->all() : null,
        ]);

        try {
            $customer = User::create([
                'name' => $request->input('name'),
                'mobile' => $mobile, // Use normalized mobile (10 digits only)
                'email' => $request->input('email'),
                'gst_number' => $request->input('gst_number') ? strtoupper($request->input('gst_number')) : null,
                'customer_type' => $customerType,
                'password' => Hash::make('password'), // Default password, customer can change later
            ]);
        } catch (QueryException $e) {
            // Handle race condition: two fast requests for same mobile.
            if ((string) $e->getCode() === '23000') {
                $existingCustomer = User::where('mobile', $mobile)->first();
                if ($existingCustomer && !$existingCustomer->isAdmin() && !$existingCustomer->isStaff()) {
                    Log::warning('POS Customer Create race handled', [
                        'mobile' => $mobile,
                        'existing_customer_id' => $existingCustomer->id,
                    ]);

                    return response()->json([
                        'success' => true,
                        'message' => 'Customer already exists. Using existing customer.',
                        'data' => [
                            'id' => $existingCustomer->id,
                            'name' => $existingCustomer->name,
                            'mobile' => $existingCustomer->mobile,
                            'email' => $existingCustomer->email,
                            'customer_type' => $existingCustomer->customer_type ?? 'retail',
                        ],
                    ], 200);
                }
            }

            throw $e;
        }

        Log::info('POS Customer Created', [
            'id' => $customer->id,
            'customer_type' => $customer->customer_type,
        ]);

        return response()->json([
            'success' => true,
            'message' => 'Customer created successfully',
            'data' => [
                'id' => $customer->id,
                'name' => $customer->name,
                'mobile' => $customer->mobile,
                'email' => $customer->email,
                'customer_type' => $customer->customer_type ?? 'retail',
            ],
        ], 201);
    }

    /**
     * List customer addresses
     */
    public function addresses(int $customerId): JsonResponse
    {
        $user = User::findOrFail($customerId);

        // Prevent fetching staff/admin addresses
        if ($user->isAdmin() || $user->isStaff()) {
            return response()->json([
                'success' => false,
                'message' => 'Invalid customer',
            ], 400);
        }

        $addresses = Address::with(['country', 'stateRelation', 'cityRelation'])
            ->where('user_id', $user->id)
            ->orderByDesc('is_default')
            ->orderByDesc('id')
            ->get()
            ->map(function ($addr) {
                return [
                    'id' => $addr->id,
                    'name' => $addr->name,
                    'mobile' => $addr->mobile,
                    'line1' => $addr->line1,
                    'line2' => $addr->line2,
                    'city' => $addr->cityRelation?->name ?? $addr->city,
                    'state' => $addr->stateRelation?->name ?? $addr->state,
                    'country' => $addr->country?->name,
                    'country_id' => $addr->country_id,
                    'state_id' => $addr->state_id,
                    'city_id' => $addr->city_id,
                    'pin' => $addr->pin,
                    'full_address' => $addr->full_address,
                ];
            });

        return response()->json([
            'success' => true,
            'data' => $addresses,
        ]);
    }

    /**
     * Store new address for customer
     */
    public function storeAddress(Request $request, int $customerId): JsonResponse
    {
        $user = User::findOrFail($customerId);

        if ($user->isAdmin() || $user->isStaff()) {
            return response()->json([
                'success' => false,
                'message' => 'Invalid customer',
            ], 400);
        }

        // Normalize mobile number - remove spaces, +91 prefix, leading 0
        $mobile = preg_replace('/\s+/', '', (string) $request->input('mobile', ''));
        $mobile = preg_replace('/^\+91/', '', $mobile);
        $mobile = ltrim($mobile, '0');
        
        // Merge normalized mobile back to request
        $request->merge(['mobile' => $mobile]);
        
        $validator = Validator::make($request->all(), [
            'name' => 'required|string|max:255',
            'mobile' => ['required', 'string', 'regex:/^[6-9]\d{9}$/', 'size:10'],
            'country_id' => ['required', 'integer', Rule::exists('countries', 'id')->where('status', 1)],
            'state_id' => [
                'required',
                'integer',
                Rule::exists('states', 'id')
                    ->where('status', 1)
                    ->where(fn ($q) => $q->where('country_id', $request->input('country_id'))),
            ],
            'city_id' => [
                'required',
                'integer',
                Rule::exists('cities', 'id')
                    ->where('status', 1)
                    ->where(fn ($q) => $q->where('state_id', $request->input('state_id'))),
            ],
            'line1' => 'required|string|max:255',
            'line2' => 'nullable|string|max:255',
            'city' => 'nullable|string|max:100',
            'state' => 'nullable|string|max:100',
            'pin' => 'required|string|regex:/^\d{6}$/',
        ], [
            'name.required' => 'Name is required',
            'mobile.required' => 'Mobile number is required',
            'mobile.regex' => 'Mobile number must be 10 digits starting with 6, 7, 8, or 9',
            'mobile.size' => 'Mobile number must be exactly 10 digits',
            'country_id.required' => 'Country is required',
            'country_id.exists' => 'Selected country is invalid',
            'state_id.required' => 'State is required',
            'state_id.exists' => 'Selected state is invalid',
            'city_id.required' => 'City is required',
            'city_id.exists' => 'Selected city is invalid',
            'line1.required' => 'Address line 1 is required',
            'pin.required' => 'Pincode is required',
            'pin.regex' => 'Pincode must be exactly 6 digits',
        ]);

        if ($validator->fails()) {
            return response()->json([
                'success' => false,
                'message' => 'Validation failed',
                'errors' => $validator->errors(),
            ], 422);
        }

        $state = State::find($request->input('state_id'));
        $city = City::find($request->input('city_id'));
        $country = Country::find($request->input('country_id'));

        // Format mobile with +91 prefix for storage
        $formattedMobile = '+91' . $mobile;
        
        $address = Address::create([
            'user_id' => $user->id,
            'name' => $request->name,
            'mobile' => $formattedMobile,
            'line1' => $request->line1,
            'line2' => $request->line2,
            'country_id' => $country?->id,
            'state_id' => $state?->id,
            'city_id' => $city?->id,
            'city' => $city?->name,
            'state' => $state?->name,
            'pin' => $request->pin,
            'is_default' => false,
        ]);

        return response()->json([
            'success' => true,
            'message' => 'Address saved',
            'data' => [
                'id' => $address->id,
                'name' => $address->name,
                'mobile' => $address->mobile,
                'line1' => $address->line1,
                'line2' => $address->line2,
                'city' => $address->city,
                'state' => $address->state,
                'pin' => $address->pin,
                'full_address' => $address->full_address,
            ],
        ], 201);
    }
}
