<?php

namespace Modules\CRMCore\App\Http\Controllers\Api\V1;

use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Validator;
use Modules\CRMCore\App\Http\Controllers\Api\BaseApiController;
use Modules\CRMCore\App\Http\Resources\CustomerResource;
use Modules\CRMCore\App\Models\CustomerGroup;
use Modules\SystemCore\App\Enums\CustomerStatus;
use Modules\SystemCore\App\Enums\CustomerType;
use Modules\SystemCore\App\Models\CoreCustomer;

class CustomerController extends BaseApiController
{
    /**
     * Display a listing of customers
     */
    public function index(Request $request): JsonResponse
    {
        try {
            $query = CoreCustomer::with(['customerGroup', 'company', 'primaryContact', 'primaryAddress', 'createdBy']);

            // Filter by customer type
            if ($request->has('customer_type')) {
                $query->where('customer_type', $request->customer_type);
            }

            // Filter by customer group
            if ($request->has('customer_group_id')) {
                $query->where('customer_group_id', $request->customer_group_id);
            }

            // Filter by status
            if ($request->has('status')) {
                switch ($request->status) {
                    case 'active':
                        $query->where('is_active', true)->where('is_blacklisted', false);
                        break;
                    case 'inactive':
                        $query->where('is_active', false);
                        break;
                    case 'blocked':
                        $query->where('is_blacklisted', true);
                        break;
                }
            }

            // Filter by company (B2B)
            if ($request->has('company_id')) {
                $query->where('company_id', $request->company_id);
            }

            // Filter by credit limit
            if ($request->has('min_credit_limit')) {
                $query->where('credit_limit', '>=', $request->min_credit_limit);
            }
            if ($request->has('max_credit_limit')) {
                $query->where('credit_limit', '<=', $request->max_credit_limit);
            }

            // Search functionality
            if ($request->has('search')) {
                $search = $request->search;
                $query->where(function ($q) use ($search) {
                    $q->where('customer_code', 'like', "%{$search}%")
                        ->orWhere('name', 'like', "%{$search}%")
                        ->orWhere('email', 'like', "%{$search}%")
                        ->orWhere('phone', 'like', "%{$search}%")
                        ->orWhere('tax_id', 'like', "%{$search}%")
                        ->orWhere('company_name', 'like', "%{$search}%");
                });
            }

            // Filter by date range
            if ($request->has('from_date')) {
                $query->whereDate('created_at', '>=', $request->from_date);
            }
            if ($request->has('to_date')) {
                $query->whereDate('created_at', '<=', $request->to_date);
            }

            // Sorting
            $sortBy = $request->input('sort_by', 'created_at');
            $sortOrder = $request->input('sort_order', 'desc');
            $query->orderBy($sortBy, $sortOrder);

            $customers = $query->paginate($request->input('per_page', 20));

            return $this->successResponse(
                CustomerResource::collection($customers),
                'Customers retrieved successfully'
            );
        } catch (\Exception $e) {
            return $this->errorResponse('Failed to retrieve customers', $e->getMessage(), 500);
        }
    }

    /**
     * Store a newly created customer
     */
    public function store(Request $request): JsonResponse
    {
        $validator = Validator::make($request->all(), [
            // Customer information
            'name' => 'required|string|max:255',
            'company_name' => 'nullable|string|max:255',
            'customer_type' => 'required|string',
            'email' => 'nullable|email|max:255',
            'phone' => 'nullable|string|max:50',
            'mobile' => 'nullable|string|max:50',
            'website' => 'nullable|url|max:255',
            'tax_id' => 'nullable|string|max:100',
            'vat_number' => 'nullable|string|max:100',

            // CRM fields
            'customer_group_id' => 'nullable|exists:customer_groups,id',
            'company_id' => 'nullable|exists:companies,id',
            'credit_limit' => 'nullable|numeric|min:0',
            'payment_terms' => 'nullable|string|in:net30,net60,cod,prepaid',
            'discount_percentage' => 'nullable|numeric|min:0|max:100',
            'tax_exempt' => 'nullable|boolean',
            'preferred_payment_method' => 'nullable|string|max:50',
            'preferred_delivery_method' => 'nullable|string|max:50',
            'notes' => 'nullable|string',
            'tags' => 'nullable|array',
        ]);

        if ($validator->fails()) {
            return $this->validationErrorResponse($validator);
        }

        try {
            DB::beginTransaction();

            $customerData = [
                'name' => $request->name,
                'company_name' => $request->company_name,
                'customer_type' => $request->customer_type,
                'status' => CustomerStatus::Active->value,
                'email' => $request->email,
                'phone' => $request->phone,
                'mobile' => $request->mobile,
                'website' => $request->website,
                'tax_id' => $request->tax_id,
                'vat_number' => $request->vat_number,
                'customer_group_id' => $request->customer_group_id,
                'company_id' => $request->company_id,
                'credit_limit' => $request->credit_limit ?? 0,
                'payment_terms' => $request->payment_terms ?? 'cod',
                'discount_percentage' => $request->discount_percentage ?? 0,
                'tax_exempt' => $request->tax_exempt ?? false,
                'preferred_payment_method' => $request->preferred_payment_method,
                'preferred_delivery_method' => $request->preferred_delivery_method,
                'notes' => $request->notes,
                'tags' => $request->tags,
                'is_active' => true,
                'is_blacklisted' => false,
                'lifetime_value' => 0,
                'purchase_count' => 0,
                'average_order_value' => 0,
                'credit_used' => 0,
                'created_by_id' => Auth::id(),
            ];

            $customer = CoreCustomer::create($customerData);
            $customer->load(['customerGroup', 'company', 'primaryContact', 'primaryAddress', 'createdBy']);

            DB::commit();

            return $this->successResponse(
                new CustomerResource($customer),
                'Customer created successfully',
                201
            );
        } catch (\Exception $e) {
            DB::rollBack();

            return $this->errorResponse('Failed to create customer', $e->getMessage(), 500);
        }
    }

    /**
     * Display the specified customer
     */
    public function show($id): JsonResponse
    {
        try {
            $customer = CoreCustomer::with(['customerGroup', 'company', 'contacts', 'addresses', 'documents', 'deals', 'createdBy'])
                ->findOrFail($id);

            return $this->successResponse(
                new CustomerResource($customer),
                'Customer retrieved successfully'
            );
        } catch (\Illuminate\Database\Eloquent\ModelNotFoundException $e) {
            return $this->notFoundResponse('Customer not found');
        } catch (\Exception $e) {
            return $this->errorResponse('Failed to retrieve customer', $e->getMessage(), 500);
        }
    }

    /**
     * Update the specified customer
     */
    public function update(Request $request, $id): JsonResponse
    {
        $validator = Validator::make($request->all(), [
            'name' => 'sometimes|string|max:255',
            'company_name' => 'nullable|string|max:255',
            'customer_type' => 'sometimes|string',
            'status' => 'sometimes|string',
            'email' => 'nullable|email|max:255',
            'phone' => 'nullable|string|max:50',
            'mobile' => 'nullable|string|max:50',
            'website' => 'nullable|url|max:255',
            'tax_id' => 'nullable|string|max:100',
            'vat_number' => 'nullable|string|max:100',
            'customer_group_id' => 'nullable|exists:customer_groups,id',
            'company_id' => 'nullable|exists:companies,id',
            'credit_limit' => 'nullable|numeric|min:0',
            'payment_terms' => 'nullable|string|in:net30,net60,cod,prepaid',
            'discount_percentage' => 'nullable|numeric|min:0|max:100',
            'tax_exempt' => 'nullable|boolean',
            'preferred_payment_method' => 'nullable|string|max:50',
            'preferred_delivery_method' => 'nullable|string|max:50',
            'notes' => 'nullable|string',
            'tags' => 'nullable|array',
            'is_active' => 'nullable|boolean',
            'is_blacklisted' => 'nullable|boolean',
            'blacklist_reason' => 'nullable|required_if:is_blacklisted,true|string',
        ]);

        if ($validator->fails()) {
            return $this->validationErrorResponse($validator);
        }

        try {
            DB::beginTransaction();

            $customer = CoreCustomer::findOrFail($id);

            $updateData = $request->only([
                'name', 'company_name', 'customer_type', 'status', 'email', 'phone', 'mobile',
                'website', 'tax_id', 'vat_number', 'customer_group_id', 'company_id',
                'credit_limit', 'payment_terms', 'discount_percentage', 'tax_exempt',
                'preferred_payment_method', 'preferred_delivery_method', 'notes', 'tags',
                'is_active', 'is_blacklisted', 'blacklist_reason',
            ]);

            $updateData['updated_by_id'] = Auth::id();
            $customer->update(array_filter($updateData, fn ($value) => $value !== null));

            $customer->load(['customerGroup', 'company', 'primaryContact', 'primaryAddress', 'createdBy']);

            DB::commit();

            return $this->successResponse(
                new CustomerResource($customer),
                'Customer updated successfully'
            );
        } catch (\Illuminate\Database\Eloquent\ModelNotFoundException $e) {
            DB::rollBack();

            return $this->notFoundResponse('Customer not found');
        } catch (\Exception $e) {
            DB::rollBack();

            return $this->errorResponse('Failed to update customer', $e->getMessage(), 500);
        }
    }

    /**
     * Remove the specified customer
     */
    public function destroy($id): JsonResponse
    {
        try {
            $customer = CoreCustomer::findOrFail($id);
            $customer->delete();

            return $this->successResponse(null, 'Customer deleted successfully');
        } catch (\Illuminate\Database\Eloquent\ModelNotFoundException $e) {
            return $this->notFoundResponse('Customer not found');
        } catch (\Exception $e) {
            return $this->errorResponse('Failed to delete customer', $e->getMessage(), 500);
        }
    }

    /**
     * Search customers
     */
    public function search(Request $request): JsonResponse
    {
        try {
            $search = $request->input('search', '');

            $customers = CoreCustomer::with(['customerGroup', 'company'])
                ->where('is_active', true)
                ->where('is_blacklisted', false)
                ->where(function ($query) use ($search) {
                    $query->where('customer_code', 'like', "%{$search}%")
                        ->orWhere('name', 'like', "%{$search}%")
                        ->orWhere('email', 'like', "%{$search}%")
                        ->orWhere('phone', 'like', "%{$search}%")
                        ->orWhere('company_name', 'like', "%{$search}%");
                })
                ->limit(10)
                ->get();

            return $this->successResponse(
                CustomerResource::collection($customers),
                'Customers retrieved successfully'
            );
        } catch (\Exception $e) {
            return $this->errorResponse('Failed to search customers', $e->getMessage(), 500);
        }
    }

    /**
     * Get customer groups
     */
    public function getGroups(): JsonResponse
    {
        try {
            $groups = CustomerGroup::where('is_active', true)
                ->orderBy('name')
                ->get();

            return $this->successResponse($groups, 'Customer groups retrieved successfully');
        } catch (\Exception $e) {
            return $this->errorResponse('Failed to retrieve customer groups', $e->getMessage(), 500);
        }
    }

    /**
     * Bulk update customer status
     */
    public function bulkUpdateStatus(Request $request): JsonResponse
    {
        $validator = Validator::make($request->all(), [
            'customer_ids' => 'required|array',
            'customer_ids.*' => 'exists:core_customers,id',
            'status' => 'required|in:active,inactive,blocked',
        ]);

        if ($validator->fails()) {
            return $this->validationErrorResponse($validator);
        }

        try {
            $updateData = ['updated_by_id' => Auth::id(), 'updated_at' => now()];

            switch ($request->status) {
                case 'active':
                    $updateData['is_active'] = true;
                    $updateData['is_blacklisted'] = false;
                    $updateData['status'] = CustomerStatus::Active->value;
                    break;
                case 'inactive':
                    $updateData['is_active'] = false;
                    $updateData['status'] = CustomerStatus::Inactive->value;
                    break;
                case 'blocked':
                    $updateData['is_blacklisted'] = true;
                    $updateData['status'] = CustomerStatus::Blocked->value;
                    break;
            }

            CoreCustomer::whereIn('id', $request->customer_ids)->update($updateData);

            return $this->successResponse(null, 'Customer statuses updated successfully');
        } catch (\Exception $e) {
            return $this->errorResponse('Failed to update customer statuses', $e->getMessage(), 500);
        }
    }

    /**
     * Get customer statistics
     */
    public function statistics(Request $request): JsonResponse
    {
        try {
            $query = CoreCustomer::query();

            // Apply date filters
            if ($request->has('from_date')) {
                $query->whereDate('created_at', '>=', $request->from_date);
            }
            if ($request->has('to_date')) {
                $query->whereDate('created_at', '<=', $request->to_date);
            }

            $stats = [
                'total_customers' => $query->count(),
                'active_customers' => (clone $query)->where('is_active', true)->where('is_blacklisted', false)->count(),
                'inactive_customers' => (clone $query)->where('is_active', false)->count(),
                'blocked_customers' => (clone $query)->where('is_blacklisted', true)->count(),
                'b2b_customers' => (clone $query)->where('customer_type', CustomerType::B2B)->count(),
                'b2c_customers' => (clone $query)->where('customer_type', CustomerType::B2C)->count(),
                'total_credit_limit' => (clone $query)->sum('credit_limit'),
                'total_lifetime_value' => (clone $query)->sum('lifetime_value'),
                'average_credit_limit' => (clone $query)->avg('credit_limit'),
                'customers_by_group' => CustomerGroup::withCount(['customers' => function ($q) use ($query) {
                    $q->whereIn('customer_group_id', (clone $query)->pluck('customer_group_id'));
                }])->get()->map(function ($group) {
                    return [
                        'id' => $group->id,
                        'name' => $group->name,
                        'count' => $group->customers_count,
                        'discount_percentage' => $group->discount_percentage,
                    ];
                }),
                'recent_customers' => (clone $query)->latest()->take(5)->get()->map(function ($customer) {
                    return [
                        'id' => $customer->id,
                        'customer_code' => $customer->customer_code,
                        'name' => $customer->name,
                        'type' => $customer->customer_type->label(),
                        'created_at' => $customer->created_at,
                    ];
                }),
            ];

            return $this->successResponse($stats, 'Customer statistics retrieved successfully');
        } catch (\Exception $e) {
            return $this->errorResponse('Failed to retrieve statistics', $e->getMessage(), 500);
        }
    }
}
