<?php

namespace App\Http\Controllers\Api;

use App\Http\Controllers\Controller;
use App\Models\Account;
use App\Models\AccountTransaction;
use App\Models\FactoryInvoice;
use App\Models\PurchaseOrder;
use App\Models\Qc;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Validator;

class PaymentController extends Controller
{
    /**
     * Get references for a specific account and type
     */
    public function getReferences(Request $request): JsonResponse
    {
        $validator = Validator::make($request->all(), [
            'type' => 'required|string|in:purchase_order,qc,payroll,factory_invoice',
            'account_id' => 'required|exists:accounts,id'
        ]);

        if ($validator->fails()) {
            return response()->json(['error' => $validator->errors()], 422);
        }

        $account = Account::findOrFail($request->account_id);
        $type = $request->type;
        $references = [];

        switch ($type) {
            case 'purchase_order':
                if ($account->model_type === 'supplier') {
                    $references = PurchaseOrder::where('contact_id', $account->model_id)
                        ->where('status', '!=', 'completed')
                        ->where('status', '!=', 'cancelled')
                        ->select('id', 'po_number as name', 'total_amount', 'status')
                        ->get()
                        ->map(function ($po) {
                            return [
                                'id' => $po->id,
                                'name' => $po->name . ' - ' . format_currency($po->total_amount) . ' (' . ucfirst($po->status) . ')'
                            ];
                        });
                }
                break;

            case 'qc':
                if ($account->model_type === 'supplier') {
                    $references = Qc::whereHas('purchaseOrder', function($q) use ($account) {
                            $q->where('contact_id', $account->model_id);
                        })
                        ->where('status', '!=', 'qc_passed')
                        ->where('status', '!=', 'cancelled')
                        ->select('id', 'qc_number as name', 'status')
                        ->with('qcItems')
                        ->get()
                        ->map(function ($qc) {
                            return [
                                'id' => $qc->id,
                                'name' => $qc->name . ' - ' . format_currency($qc->total_amount) . ' (' . ucfirst(str_replace('_', ' ', $qc->status)) . ')'
                            ];
                        });
                }
                break;

            case 'factory_invoice':
                if (in_array($account->model_type, ['customer', 'shop', 'distributor'])) {
                    $references = FactoryInvoice::where('customer_account_id', $account->id)
                        ->where('status', '!=', 'completed')
                        ->where('status', '!=', 'cancelled')
                        ->select('id', 'invoice_number as name', 'net_total as total_amount', 'status')
                        ->get()
                        ->map(function ($invoice) {
                            return [
                                'id' => $invoice->id,
                                'name' => $invoice->name . ' - ' . format_currency($invoice->total_amount) . ' (' . ucfirst($invoice->status) . ')'
                            ];
                        });
                }
                break;

            case 'payroll':
                // For future implementation - payroll system
                $references = [];
                break;
        }

        return response()->json($references);
    }

    /**
     * Process a payment
     */
    public function processPayment(Request $request): JsonResponse
    {
        $validator = Validator::make($request->all(), [
            'account_id' => 'required|exists:accounts,id',
            'payment_type' => 'required|string|in:purchase_order,qc,payroll',
            'reference_id' => 'required|integer',
            'amount' => 'required|numeric|min:0.01',
            'payment_method' => 'required|string|in:cash,bank_transfer,cheque',
            'notes' => 'nullable|string|max:500'
        ]);

        if ($validator->fails()) {
            return response()->json(['error' => $validator->errors()], 422);
        }

        // dd($request->account_id);
        $account = Account::findOrFail($request->account_id);

        // Validate account type matches payment type
        $validCombinations = [
            'purchase_order' => ['supplier'],
            'qc' => ['supplier'],
            'payroll' => ['employee', 'shop_employee', 'shop_manager']
        ];

        if (!in_array($account->model_type, $validCombinations[$request->payment_type] ?? [])) {
            return response()->json(['error' => 'Invalid payment type for this account'], 422);
        }

        DB::beginTransaction();
        try {
            // Validate reference exists and get it
            $reference = $this->getReferenceModel($request->payment_type, $request->reference_id);
            if (!$reference) {
                throw new \Exception('Reference not found');
            }
            // dd($reference);
            // Check if reference belongs to the account
            if (!$this->validateReferenceBelongsToAccount($reference, $account, $request->payment_type)) {
                throw new \Exception('Reference does not belong to this account');
            }


            $transaction_type =null;
            if($account->model_type === 'supplier') {
                $transaction_type = 'debit';
            }
            if($account->model_type === 'employee') {
                $transaction_type = 'credit';
            }
            if($account->model_type === 'shop' || $account->model_type === 'shop_manager' || $account->model_type === 'customer') {
                $transaction_type = 'credit';
            }

            // Create transaction
            $transaction = AccountTransaction::create([
                'account_id' => $account->id,
                'chart_of_account_id' => $account->chart_of_account_id,
                'amount' => $request->amount,
                'transaction_type' => $transaction_type, // Payment reduces what we owe (credit to account)
                'reference_id' => $request->reference_id,
                'reference_type' => $this->getReferenceType($request->payment_type),
                'description' => $request->notes ?? 'Payment processed',
            ]);

            // Update reference status if payment covers the full amount
            $this->updateReferenceStatus($reference, $request->payment_type, $request->amount);

            // Update account balance
            $account->balance -= $request->amount;
            $account->save();

            DB::commit();

            return response()->json([
                'success' => true,
                'message' => 'Payment processed successfully',
                'transaction' => $transaction
            ]);

        } catch (\Exception $e) {
            DB::rollBack();
            return response()->json(['error' => $e->getMessage()], 500);
        }
    }

    /**
     * Process a receipt
     */
    public function processReceipt(Request $request): JsonResponse
    {
        $validator = Validator::make($request->all(), [
            'account_id' => 'required|exists:accounts,id',
            'receipt_type' => 'required|string|in:factory_invoice',
            'reference_id' => 'required|integer',
            'amount' => 'required|numeric|min:0.01',
            'payment_method' => 'required|string|in:cash,bank_transfer,cheque',
            'notes' => 'nullable|string|max:500'
        ]);

        if ($validator->fails()) {
            return response()->json(['error' => $validator->errors()], 422);
        }
        // dd($request->account_id);
        $account = Account::findOrFail($request->account_id);
        // dd($account);
        // Validate account type for receipts
        if (!in_array($account->model_type, ['customer', 'shop', 'distributor'])) {
            return response()->json(['error' => 'Invalid receipt type for this account'], 422);
        }

        DB::beginTransaction();
        try {
            // Validate reference exists and get it
            $reference = $this->getReferenceModel($request->receipt_type, $request->reference_id);
            if (!$reference) {
                throw new \Exception('Reference not found');
            }
            // dd($reference);
            // Check if reference belongs to the account
            if (!$this->validateReferenceBelongsToAccount($reference, $account, $request->receipt_type)) {
                throw new \Exception('Reference does not belong to this account');
            }

            // Create transaction
            $transaction = AccountTransaction::create([
                'account_id' => $account->id,
                'chart_of_account_id' => $account->chart_of_account_id,
                'amount' => $request->amount,
                'transaction_type' => 'credit', // Receipt increases what they owe us (debit to account)
                'reference_id' => $request->reference_id,
                'reference_type' => $this->getReferenceType($request->receipt_type),
                'description' => $request->notes ?? 'Receipt processed',
            ]);

            // Update reference status if receipt covers the full amount
            $this->updateReferenceStatus($reference, $request->receipt_type, $request->amount);

            // Update account balance
            $account->balance += $request->amount;
            $account->save();

            DB::commit();

            return response()->json([
                'success' => true,
                'message' => 'Receipt processed successfully',
                'transaction' => $transaction
            ]);

        } catch (\Exception $e) {
            DB::rollBack();
            return response()->json(['error' => $e->getMessage()], 500);
        }
    }

    private function getReferenceModel($type, $id)
    {
        switch ($type) {
            case 'purchase_order':
                return PurchaseOrder::find($id);
            case 'qc':
                return Qc::find($id);
            case 'factory_invoice':
                return FactoryInvoice::find($id);
            default:
                return null;
        }
    }

    private function validateReferenceBelongsToAccount($reference, Account $account, $type): bool
    {
        // dd($type);
        if (!$reference) return false;
        switch ($type) {
            case 'purchase_order':
                return $reference->contact_id == $account->model_id;
            case 'qc':
                // For QC, check if the related purchase order belongs to the supplier
                return $reference->purchaseOrder && $reference->purchaseOrder->contact_id == $account->model_id;
            case 'factory_invoice':
                // dd($account->model_id);
                return $reference->customer_account_id == $account->id;
            case 'payroll':
                return $reference->employee_account_id == $account->model_id;
            case 'shop_employee':
                return $reference->shop_employee_account_id == $account->model_id;
            case 'shop_manager':
                return $reference->shop_manager_account_id == $account->model_id;
            case 'distributor':
                return $reference->distributor_account_id == $account->model_id;
            case 'customer':
                return $reference->customer_account_id == $account->model_id;
            case 'shop':
                return $reference->shop_account_id == $account->model_id;
            case 'supplier':
                return $reference->supplier_account_id == $account->model_id;
            case 'employee':
                return $reference->employee_account_id == $account->model_id;
            case 'shop_employee':
                return $reference->shop_employee_account_id == $account->model_id;
            case 'shop_manager':
                return $reference->shop_manager_account_id == $account->model_id;
            case 'distributor':
                return $reference->distributor_account_id == $account->model_id;
            case 'customer':
                return $reference->customer_account_id == $account->model_id;
            case 'shop':
                return $reference->shop_account_id == $account->model_id;
            case 'supplier':
                return $reference->supplier_account_id == $account->model_id;
            case 'employee':
                return $reference->employee_account_id == $account->model_id;
            case 'shop_employee':
                return $reference->shop_employee_account_id == $account->model_id;
            case 'shop_manager':
                return $reference->shop_manager_account_id == $account->model_id;
            case 'distributor':
                return $reference->distributor_account_id == $account->model_id;
            case 'customer':
                return $reference->customer_account_id == $account->model_id;
            case 'shop':
                return $reference->shop_account_id == $account->model_id;
            case 'supplier':
                return $reference->supplier_account_id == $account->model_id;
            case 'employee':
                return $reference->employee_account_id == $account->model_id;
            case 'shop_employee':
                return $reference->shop_employee_account_id == $account->model_id;
            case 'shop_manager':
                return $reference->shop_manager_account_id == $account->model_id;
            case 'distributor':
                return $reference->distributor_account_id == $account->model_id;
            default:
                return false;
        }
    }

    private function getReferenceType($type): string
    {
        // dd($type);
        $types = [
            'purchase_order' => 'App\Models\PurchaseOrder',
            'qc' => 'App\Models\Qc',
            'factory_invoice' => 'App\Models\FactoryInvoice',
            'payroll' => 'App\Models\Payroll'
        ];

        return $types[$type] ?? '';
    }

    private function getPaymentChartOfAccountId($paymentMethod): int
    {
        // This should be configurable, but for now using hardcoded IDs
        // You might want to create a config or settings table for this
        $chartAccounts = [
            'cash' => 1, // Cash account
            'bank_transfer' => 2, // Bank account
            'cheque' => 3, // Cheque account
        ];

        return $chartAccounts[$paymentMethod] ?? 1;
    }

    private function getReceiptChartOfAccountId($paymentMethod): int
    {
        // Same as payment but could be different chart of accounts
        return $this->getPaymentChartOfAccountId($paymentMethod);
    }

    private function updateReferenceStatus($reference, $type, $amount)
    {
        if (!$reference) return;

        // Check if payment/receipt covers the full amount
        $totalPaid = $reference->payments()->sum('amount') + $amount;

        switch ($type) {
            case 'purchase_order':
                if ($totalPaid >= $reference->total_amount) {
                    $reference->payment_status = PurchaseOrder::PAYMENT_STATUS_PAID;
                } elseif ($totalPaid > 0) {
                    $reference->payment_status = PurchaseOrder::PAYMENT_STATUS_PARTIALLY_PAID;
                }
                break;

            case 'qc':
                // QC doesn't have payment status, might complete when paid
                if ($totalPaid >= $reference->total_amount) {
                    // Keep current status or mark as paid if needed
                }
                break;

            case 'factory_invoice':
                // Factory invoice status is about delivery, not payment
                // Payment completion doesn't change the invoice status
                break;
        }

        $reference->save();
    }
}
