<?php

namespace App\Http\Controllers\Api;

use App\Helpers\NumberHelper;
use App\Http\Controllers\Controller;
use App\Http\Requests\Customer\StoreCustomerRequest;
use App\Http\Requests\Customer\UpdateCustomerRequest;
use App\Http\Resources\CustomerCollection;
use App\Http\Resources\CustomerResource;
use App\Models\User;
use App\Models\Transaction;
use App\Models\TransactionAllocation;
use App\Services\AllocationService;
use App\Services\MoneyBalanceService;
use App\Services\MetalBalanceService;
use App\Services\PlanLimitService;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Hash;

class CustomerController extends Controller
{
    public function __construct(
        protected MoneyBalanceService $moneyBalanceService,
        protected MetalBalanceService $metalBalanceService,
        protected AllocationService $allocationService,
        protected PlanLimitService $planLimitService
    ) {
    }

    /**
     * Get base query for customers (users with is_customer = true).
     */
    protected function customersQuery()
    {
        return User::where('is_customer', true);
    }

    public function index(Request $request)
    {
        $query = $this->customersQuery();

        // Status filters
        if ($status = $request->query('status')) {
            if ($status === 'active') {
                $query->where('is_active', true);
            } elseif ($status === 'inactive') {
                $query->where('is_active', false);
            }
        }

        if ($search = $request->query('search')) {
            // Convert Persian/Arabic digits to English for numeric fields
            $normalizedSearch = NumberHelper::persianToEnglish($search);
            
            $query->where(function ($q) use ($search, $normalizedSearch) {
                // Search in name with original search term (may contain Persian/Arabic)
                $q->where('name', 'like', "%{$search}%")
                    // Search in numeric fields with normalized (English) digits
                    ->orWhere('mobile', 'like', "%{$normalizedSearch}%");
            });
        }

        // Date filter for created_at
        if ($from = $request->query('from_date')) {
            $query->whereDate('created_at', '>=', $from);
        }

        if ($to = $request->query('to_date')) {
            $query->whereDate('created_at', '<=', $to);
        }

        // Balance filter - requires post-query filtering
        $balanceFilter = $request->query('balance'); // money_debtor, money_creditor, metal_debtor, metal_creditor
        
        if ($balanceFilter) {
            $customers = $query->orderBy('id', 'desc')->get();
            
            $filtered = $customers->filter(function ($customer) use ($balanceFilter) {
                if (in_array($balanceFilter, ['money_debtor', 'money_creditor'])) {
                    $summary = $this->moneyBalanceService->getCustomerMoneyBalanceSummary($customer);
                    if ($balanceFilter === 'money_debtor') {
                        return $summary['debt'] > 0.01;
                    } else {
                        return $summary['credit'] > 0.01;
                    }
                } elseif (in_array($balanceFilter, ['metal_debtor', 'metal_creditor'])) {
                    $summary = $this->metalBalanceService->getCustomerMetalBalanceSummary($customer);
                    // بدهکار فلزی = خرید از مشتری (سیستم طلبکار فلز است، مشتری بدهکار فلز است)
                    // طلبکار فلزی = فروش به مشتری (سیستم بدهکار فلز است، مشتری طلبکار فلز است)
                    if ($balanceFilter === 'metal_debtor') {
                        return $summary['total_debt_grams'] > 0.001;
                    } else {
                        return $summary['total_credit_grams'] > 0.001;
                    }
                }
                return true;
            });

            $filtered->each(function ($customer) {
                $money = $this->moneyBalanceService->getCustomerMoneyBalanceSummary($customer);
                $metal = $this->metalBalanceService->getCustomerMetalBalanceSummary($customer);
                $customer->money_debt = round($money['debt'], 2);
                $customer->money_credit = round($money['credit'], 2);
                $customer->metal_debt_grams = round($metal['total_debt_grams'], 6);
                $customer->metal_credit_grams = round($metal['total_credit_grams'], 6);
                $customer->metal_balances = $metal['balances'];
            });

            $items = $filtered->values();
            $total = $items->count();

            return $this->success([
                'data' => CustomerResource::collection($items),
                'total' => $total,
                'current_page' => 1,
                'last_page' => 1,
                'per_page' => $total,
            ]);
        }

        $allowedSort = ['id', 'name', 'code', 'mobile', 'created_at'];
        $sortBy = $request->query('sort', 'id');
        $sortOrder = strtolower($request->query('order', 'desc')) === 'asc' ? 'asc' : 'desc';
        if (! in_array($sortBy, $allowedSort)) {
            $sortBy = 'id';
        }

        $perPage = $request->query('per_page', 15);
        $customers = $query->orderBy($sortBy, $sortOrder)->paginate($perPage);

        $withBalance = $request->query('with_balance') === '1' || $request->query('with_balance') === 'true';
        if ($withBalance) {
            $customers->getCollection()->transform(function ($customer) {
                $money = $this->moneyBalanceService->getCustomerMoneyBalanceSummary($customer);
                $metal = $this->metalBalanceService->getCustomerMetalBalanceSummary($customer);
                $customer->money_debt = round($money['debt'], 2);
                $customer->money_credit = round($money['credit'], 2);
                $customer->metal_debt_grams = round($metal['total_debt_grams'], 6);
                $customer->metal_credit_grams = round($metal['total_credit_grams'], 6);
                $customer->metal_balances = $metal['balances'];
                return $customer;
            });
        }

        return $this->success($customers);
    }

    public function store(StoreCustomerRequest $request)
    {
        $vendor = current_vendor();
        if ($vendor && ! $this->planLimitService->canAddCustomer($vendor)) {
            return $this->error('به سقف تعداد مشتریان پلن فعلی رسیده‌اید. لطفاً پلن را ارتقا دهید.', 422);
        }

        $data = $request->validated();

        // Force delete any soft-deleted customers with the same mobile
        // This allows reusing the mobile number as username
        User::onlyTrashed()->where('mobile', $data['mobile'])->forceDelete();

        // Username is the mobile number
        $username = $data['mobile'];

        $customer = User::create([
            'name' => $data['name'],
            'username' => $username,
            'password' => Hash::make('customer123'), // Default password
            'mobile' => $data['mobile'],
            'notes' => $data['notes'] ?? null,
            'bank_accounts' => $data['bank_accounts'] ?? null,
            'is_active' => $data['is_active'] ?? true,
            'is_customer' => true,
            'is_featured' => $data['is_featured'] ?? false,
        ]);

        // Assign customer role
        $customerRole = \App\Models\Role::where('name', 'customer')->first();
        if ($customerRole) {
            $customer->roles()->attach($customerRole->id);
        }

        return $this->created(
            new CustomerResource($customer),
            'مشتری با موفقیت ایجاد شد'
        );
    }

    public function show($id)
    {
        if (!$id || $id === 'null') {
            return $this->notFound('مشتری یافت نشد');
        }

        $customer = $this->customersQuery()->find($id);
        if (!$customer) {
            return $this->notFound('مشتری یافت نشد');
        }

        return $this->success(new CustomerResource($customer));
    }

    public function update(UpdateCustomerRequest $request, $id)
    {
        if (!$id || $id === 'null') {
            return $this->notFound('مشتری یافت نشد');
        }

        $customer = $this->customersQuery()->find($id);
        if (!$customer) {
            return $this->notFound('مشتری یافت نشد');
        }

        $data = $request->validated();
        $customer->update($data);

        return $this->success(
            new CustomerResource($customer),
            'مشتری با موفقیت بروزرسانی شد'
        );
    }

    public function destroy($id)
    {
        if (!$id || $id === 'null') {
            return $this->notFound('مشتری یافت نشد');
        }

        $customer = $this->customersQuery()->find($id);
        if (!$customer) {
            return $this->notFound('مشتری یافت نشد');
        }

        $customer->delete();

        return $this->success(null, 'مشتری حذف شد');
    }

    public function balance($id)
    {
        if (!$id || $id === 'null') {
            return $this->notFound('مشتری یافت نشد');
        }

        $customer = $this->customersQuery()->find($id);
        if (!$customer) {
            return $this->notFound('مشتری یافت نشد');
        }

        // Calculate money balance
        $moneyBalance = $this->moneyBalanceService->getCustomerMoneyBalanceSummary($customer);

        // Calculate metal balance
        $metalBalance = $this->metalBalanceService->getCustomerMetalBalanceSummary($customer);

        return $this->success([
            'customer' => new CustomerResource($customer),
            'money' => [
                'total_debit' => $moneyBalance['total_debit'],
                'total_credit' => $moneyBalance['total_credit'],
                'debt' => $moneyBalance['debt'],
                'credit' => $moneyBalance['credit'],
            ],
            'metal' => [
                'balances' => $metalBalance['balances'],
                'total_debt_grams' => $metalBalance['total_debt_grams'],
                'total_credit_grams' => $metalBalance['total_credit_grams'],
            ],
        ]);
    }

    /**
     * Get customer transactions history (transactions from/to this customer).
     */
    public function transactions(Request $request, $id)
    {
        if (!$id || $id === 'null') {
            return $this->notFound('مشتری یافت نشد');
        }

        $customer = $this->customersQuery()->find($id);
        if (!$customer) {
            return $this->notFound('مشتری یافت نشد');
        }

        $query = Transaction::with(['fromUser', 'toUser', 'allocations'])
            ->where(function ($q) use ($customer) {
                $q->where('from_user_id', $customer->id)
                    ->orWhere('to_user_id', $customer->id);
            });

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

        if ($from = $request->query('from_date')) {
            $query->whereDate('transaction_date', '>=', $from);
        }

        if ($to = $request->query('to_date')) {
            $query->whereDate('transaction_date', '<=', $to);
        }

        $transactions = $query->orderBy('transaction_date', 'desc')->paginate();

        // Add remaining amount for each transaction
        $transactions->getCollection()->transform(function ($transaction) {
            $transaction->remaining_amount = $this->allocationService->getRemainingAmount($transaction);
            return $transaction;
        });

        return $this->success($transactions);
    }

    /**
     * Get customer allocations history.
     */
    public function allocations(Request $request, $id)
    {
        if (!$id || $id === 'null') {
            return $this->notFound('مشتری یافت نشد');
        }

        $customer = $this->customersQuery()->find($id);
        if (!$customer) {
            return $this->notFound('مشتری یافت نشد');
        }

        $query = TransactionAllocation::with(['transaction', 'debtorUser', 'creditorUser'])
            ->where(function ($q) use ($customer) {
                $q->where('debtor_user_id', $customer->id)
                    ->orWhere('creditor_user_id', $customer->id);
            });

        $allocations = $query->orderBy('created_at', 'desc')->paginate();

        return $this->success($allocations);
    }

    /**
     * Get customer metal balance.
     */
    public function metalBalance($id)
    {
        if (!$id || $id === 'null') {
            return $this->notFound('مشتری یافت نشد');
        }

        $customer = $this->customersQuery()->find($id);
        if (!$customer) {
            return $this->notFound('مشتری یافت نشد');
        }

        $balanceSummary = $this->metalBalanceService->getCustomerMetalBalanceSummary($customer);

        return $this->success([
            'customer' => new CustomerResource($customer),
            'balances' => $balanceSummary['balances'],
            'total_debt_grams' => $balanceSummary['total_debt_grams'],
            'total_credit_grams' => $balanceSummary['total_credit_grams'],
        ]);
    }

    /**
     * Get all customers with metal credit (سیستم بدهکار فلز است، مشتری طلبکار فلز است - فروش به مشتری).
     */
    public function metalCreditors(Request $request)
    {
        $productId = $request->query('product_id') ? (int) $request->query('product_id') : null;
        $minGrams = (float) $request->query('min_grams', 0.001);
        $excludeUserId = $request->query('exclude_customer_id') ?? $request->query('exclude_user_id');

        $customers = $this->customersQuery()
            ->where('is_active', true)
            ->get();

        $result = [];

        foreach ($customers as $customer) {
            if ($excludeUserId && $customer->id == $excludeUserId) {
                continue;
            }

            $balanceSummary = $this->metalBalanceService->getCustomerMetalBalanceSummary($customer);
            
            $creditBalances = $balanceSummary['balances']->filter(function ($balance) use ($productId, $minGrams) {
                if ($balance['credit_grams'] < $minGrams) {
                    return false;
                }
                if ($productId !== null && (int) $balance['product_id'] !== $productId) {
                    return false;
                }
                return true;
            });

            if ($creditBalances->isNotEmpty()) {
                $result[] = [
                    'customer' => new CustomerResource($customer),
                    'balances' => $creditBalances->values(),
                    'total_credit_grams' => $balanceSummary['total_credit_grams'],
                ];
            }
        }

        return $this->success($result);
    }

    /**
     * Get all customers with metal debt (سیستم طلبکار فلز است، مشتری بدهکار فلز است - خرید از مشتری).
     */
    public function metalDebtors(Request $request)
    {
        $productId = $request->query('product_id') ? (int) $request->query('product_id') : null;
        $minGrams = (float) $request->query('min_grams', 0.001);
        $excludeUserId = $request->query('exclude_customer_id') ?? $request->query('exclude_user_id');

        $customers = $this->customersQuery()
            ->where('is_active', true)
            ->get();

        $result = [];

        foreach ($customers as $customer) {
            if ($excludeUserId && $customer->id == $excludeUserId) {
                continue;
            }

            $balanceSummary = $this->metalBalanceService->getCustomerMetalBalanceSummary($customer);
            
            $debtBalances = $balanceSummary['balances']->filter(function ($balance) use ($productId, $minGrams) {
                if ($balance['debt_grams'] < $minGrams) {
                    return false;
                }
                if ($productId !== null && (int) $balance['product_id'] !== $productId) {
                    return false;
                }
                return true;
            });

            if ($debtBalances->isNotEmpty()) {
                $result[] = [
                    'customer' => new CustomerResource($customer),
                    'balances' => $debtBalances->values(),
                    'total_debt_grams' => $balanceSummary['total_debt_grams'],
                ];
            }
        }

        return $this->success($result);
    }

    /**
     * Get all customers with money credit (سیستم بدهکار پولی است، مشتری طلبکار پول است - خرید از مشتری).
     */
    public function moneyCreditors(Request $request)
    {
        $minAmount = (float) $request->query('min_amount', 0.01);
        $excludeUserId = $request->query('exclude_customer_id') ?? $request->query('exclude_user_id');

        $customers = $this->customersQuery()
            ->where('is_active', true)
            ->get();

        $result = [];

        foreach ($customers as $customer) {
            if ($excludeUserId && $customer->id == $excludeUserId) {
                continue;
            }

            $balanceSummary = $this->moneyBalanceService->getCustomerMoneyBalanceSummary($customer);
            
            if ($balanceSummary['credit'] >= $minAmount) {
                $result[] = [
                    'customer' => new CustomerResource($customer),
                    'total_debit' => $balanceSummary['total_debit'],
                    'total_credit' => $balanceSummary['total_credit'],
                    'credit' => $balanceSummary['credit'],
                ];
            }
        }

        // Sort by credit amount descending
        usort($result, fn($a, $b) => $b['credit'] <=> $a['credit']);

        return $this->success($result);
    }

    /**
     * Get all customers with money debt (سیستم طلبکار مالی است، مشتری بدهکار پول است - فروش به مشتری).
     */
    public function moneyDebtors(Request $request)
    {
        $minAmount = (float) $request->query('min_amount', 0.01);
        $excludeUserId = $request->query('exclude_customer_id') ?? $request->query('exclude_user_id');

        $customers = $this->customersQuery()
            ->where('is_active', true)
            ->get();

        $result = [];

        foreach ($customers as $customer) {
            if ($excludeUserId && $customer->id == $excludeUserId) {
                continue;
            }

            $balanceSummary = $this->moneyBalanceService->getCustomerMoneyBalanceSummary($customer);
            
            if ($balanceSummary['debt'] >= $minAmount) {
                $result[] = [
                    'customer' => new CustomerResource($customer),
                    'total_debit' => $balanceSummary['total_debit'],
                    'total_credit' => $balanceSummary['total_credit'],
                    'debt' => $balanceSummary['debt'],
                ];
            }
        }

        // Sort by debt amount descending
        usort($result, fn($a, $b) => $b['debt'] <=> $a['debt']);

        return $this->success($result);
    }

    /**
     * Get all customers with their complete balances (money + metal).
     */
    public function allBalances(Request $request)
    {
        $nonZeroOnly = $request->query('non_zero') === 'true';
        $excludeUserId = $request->query('exclude_customer_id') ?? $request->query('exclude_user_id');

        $customers = $this->customersQuery()
            ->where('is_active', true)
            ->get();

        $result = [];

        foreach ($customers as $customer) {
            if ($excludeUserId && $customer->id == $excludeUserId) {
                continue;
            }

            $moneyBalance = $this->moneyBalanceService->getCustomerMoneyBalanceSummary($customer);
            $metalBalance = $this->metalBalanceService->getCustomerMetalBalanceSummary($customer);

            $hasBalance = $moneyBalance['debt'] > 0.01 
                || $moneyBalance['credit'] > 0.01
                || $metalBalance['total_debt_grams'] > 0.001
                || $metalBalance['total_credit_grams'] > 0.001;

            if ($nonZeroOnly && !$hasBalance) {
                continue;
            }

            $result[] = [
                'customer' => new CustomerResource($customer),
                'money' => [
                    'debt' => $moneyBalance['debt'],
                    'credit' => $moneyBalance['credit'],
                ],
                'metal' => [
                    'balances' => $metalBalance['balances'],
                    'total_debt_grams' => $metalBalance['total_debt_grams'],
                    'total_credit_grams' => $metalBalance['total_credit_grams'],
                ],
            ];
        }

        return $this->success($result);
    }
}
