<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Models;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use App\Models\Merchant;
use App\Models\Transaction;
use App\ActivityLog;
use App\Libs\Smsgateway;

class ApiMerchantsController extends Controller{
    public function merchant_login(Request $request){
        $this->validate($request, [
            'phone_number' => 'required',
            'pin' => 'required'
        ]);
        $phone_number = $this->validatePhoneNumber($request->phone_number);

        if ($phone_number === false) {
            return response()->json([
                'success' => false,
                'message' => 'Phone Number/PIN is incorrect!'
            ], 401);
        }

        $pin = md5($request->input('pin'));

        $merchant = Models\Merchant::where('phone', $phone_number)->where('pin', $pin)->first();

        if ($merchant === null) {
            return response()->json([
                'success' => false,
                'message' => 'Phone Number/PIN incorrect!'
            ], 401);
        }
        return response()->json([
            'success' => true,
            'message' => 'Login successful',
            'merchant' => [
                'id' => $merchant->id,
                'phone' => $merchant->phone,
                'balance' => $merchant->balance,
                'status' => $merchant->status,
                'fullname' => $merchant->fullname,
                'country' => $merchant->country
            ]
        ], 200);
    }

    
    public function get_transactions(Request $request)
    {
        // POST body params: merchant_id (required), keyword (optional), start_date, end_date, per_page
        $merchantId = $request->input('merchant_id');

        if (!$merchantId) {
            return response()->json(['success' => false, 'message' => 'merchant_id is required'], 422);
        }
        $merchant = Models\Merchant::find($merchantId);
        if (!$merchant) {
            return response()->json(['success' => false, 'message' => 'merchant not found'], 404);
        }

        $perPage = (int) $request->input('per_page', 20);

        $query = \DB::table('transactions')
            ->join('merchants', 'transactions.merchant_id', '=', 'merchants.id')
            ->select(
                'merchants.fullname',
                'transactions.id',
                'transactions.status',
                'transactions.msisdn',
                'transactions.amount',
                'transactions.created_at'
            )
            ->where('transactions.merchant_id', $merchantId);

        if ($request->filled('keyword')) {
            $keyword = $request->input('keyword');
            $like = "%{$keyword}%";
            $query->where(function ($q) use ($like) {
                $q->where('merchants.fullname', 'like', $like)
                  ->orWhere('transactions.msisdn', 'like', $like)
                  ->orWhere('transactions.status', 'like', $like)
                  ->orWhere('transactions.amount', 'like', $like)
                  ->orWhere('transactions.created_at', 'like', $like);
            });
        }

        if ($request->filled('start_date') || $request->filled('end_date')) {
            try {
                $start = $request->filled('start_date') ? \Carbon\Carbon::parse($request->input('start_date'))->startOfDay() : null;
                $end = $request->filled('end_date') ? \Carbon\Carbon::parse($request->input('end_date'))->endOfDay() : null;
            } catch (\Exception $e) {
                return response()->json(['success' => false, 'message' => 'Invalid date format'], 422);
            }

            if ($start && $end) {
                $query->whereBetween('transactions.created_at', [$start, $end]);
            } elseif ($start) {
                $query->where('transactions.created_at', '>=', $start);
            } else {
                $query->where('transactions.created_at', '<=', $end);
            }
        }

        $query->orderBy('transactions.created_at', 'desc');

        $paginator = $query->paginate($perPage)->appends($request->except('page'));

        return response()->json($paginator);
    }
    public function get_dealers(Request $request){
        $perPage = (int) $request->input('per_page', 20);

        #$dealer_arr = \DB::table('organisations')->orderBy('organisations.created_at', 'DESC')->paginate(20);

        $query = \DB::table('organisations')->select('organisations.id', 'organisations.name', 'organisations.email', 'organisations.phone', 'organisations.status');

        if ($request->filled('keyword')) {
            $keyword = $request->input('keyword');
            $like = "%{$keyword}%";
            $query->where(function ($q) use ($like) {
                $q->where('organisations.name', 'like', $like)
                  ->orWhere('organisations.phone', 'like', $like)
                  ->orWhere('organisations.email', 'like', $like)
                  ->orWhere('organisations.status', 'like', $like)
                  ->orWhere('organisations.created_at', 'like', $like);
            });
        }
        $paginator = $query->paginate($perPage)->appends($request->except('page'));

        return response()->json($paginator);
    }
    
    public function getDealerTransactionsJson(Request $request){
        $merchant_id = session('merchant.id');
        // dd($merchant_id);
        $transactions_arr = \DB::table('merchant_top_ups')
            ->join('merchants', 'merchant_top_ups.merchant_id', '=', 'merchants.id')
            ->join('org_users', 'merchant_top_ups.org_user_id', '=', 'org_users.id')
            ->select('merchants.fullname', 'org_users.phone', 'org_users.name', 'merchant_top_ups.id', 'merchant_top_ups.status', 'merchant_top_ups.amount', 'merchant_top_ups.created_at')
            ->whereRaw('merchant_top_ups.merchant_id = '. $merchant_id)
            ->orderBy('merchant_top_ups.created_at', 'DESC')
            ->paginate(20);

        if($request->has('keyword')){
            $queries = [];
            $keyword = $request->keyword;
            $queries['keyword'] = $keyword;
            $transactions_arr = \DB::table('merchant_top_ups')
                ->join('merchants', 'merchant_top_ups.merchant_id', '=', 'merchants.id')
                ->join('org_users', 'merchant_top_ups.org_user_id', '=', 'org_users.id')
                ->select('merchants.fullname', 'org_users.phone', 'org_users.name', 'merchant_top_ups.id', 'merchant_top_ups.status', 'merchant_top_ups.amount', 'merchant_top_ups.created_at')
                ->whereRaw("org_users.phone LIKE '%$keyword%' OR org_users.name LIKE '%$keyword%' OR merchants.fullname LIKE '%$keyword%' OR merchant_top_ups.status LIKE '%$keyword%' OR merchant_top_ups.amount LIKE '%$keyword%' OR merchant_top_ups.created_at LIKE '%$keyword%'")
                ->whereRaw('merchant_top_ups.merchant_id = '. $merchant_id)
                ->orderBy('merchant_top_ups.created_at', 'DESC')
                ->paginate(20)->appends($queries);
        }
        return response()->json($transactions_arr);
    }
   

    public function merchant_transactions($merchant){

        $transactions = Models\Transaction::where('merchant_id', $merchant->id)
                ->select('id', 'created_at')->get()
                ->groupBy(function($date) {
                    return Carbon::parse($date->created_at)->format('m'); // grouping by months
                });
        $transactionmcount = [];
        $transactionArr = [];
        
        

        $pp = 1;
        $trans = [];
        foreach ($transactions as $value) {
            if ($pp == $value) {
                $trans[$pp]= $value;
            }
            else{
                $trans[$pp] = 0;
            }
            
        }
        foreach ($transactions as $key => $value) {
            $transactionmcount[(int)$key] = count($value);
        }
        for($i = 1; $i <= 12; $i++){
            if(!empty($transactionmcount[$i])){
                $transactionArr[$i] = $transactionmcount[$i];
            }else{
                $transactionArr[$i] = 0;
            }
        }

        $transactions = '';
        foreach ($transactionArr as $tran) {
            $transactions = $transactions.','.$tran;
        }
        return response()->json(['transactions' => $transactions]);
    }
    public function customerTopupStoreOld(Request $request){
        $this->validate($request, [
            'phone_number'=> 'required|numeric',
            'amount' => 'required|numeric|min:1',
            'merchant_id' => 'required|numeric'
        ]);
        $phone_number = preg_replace('/\s+/', '', $request->phone_number);
        $check_phone = $this->validatePhoneNumber($phone_number);
        if ($check_phone == false) {
            return response()->json([
                'success' => false,
                'message' => 'Invalid phone number!'
            ], 401);
        }
        $merchant = Models\Merchant::with('orgInfo')->find($request->merchant_id);
        if ($merchant == false) {
            return response()->json([
                'success' => false,
                'message' => 'merchant not found!'
            ], 401);
        }
        $difference = $merchant->balance - $request->amount;
        if ($merchant->balance < $request->amount) {
            return response()->json([
                'success' => false,
                'message' => 'Insufficient balance!'
            ], 401);
        }
        $prev_balance = $merchant->balance;
        $extRefId = uniqid() . '-' . date('YmdHis');
        $transaction_arr = [
           'msisdn' => $check_phone, 
           'amount' => $request->amount,
           'merchant_id' => $merchant->id, 
           'session_id' => $extRefId
        ];
        // dd($transaction_arr);
        $trans_result = Models\Transaction::create($transaction_arr);
        $transaction_id = $trans_result->id;
        
        $click_params = [
            "msisdn" => $check_phone,
            "amount" => $request->amount,
            "extRefId" => $extRefId
        ];
        \Log::info($click_params);

        $topup_result =  $this->ClickADPHttp($click_params);
        
        \Log::info($topup_result);

        $this->sendNtfy($topup_result);
        $topup_result_arr = json_decode($topup_result, TRUE);

        \Log::info($topup_result_arr);
        if ($topup_result == false) {
            return response()->json([
                'success' => false,
                'message' => 'Top Up Could not be processed at this time. Try again later.'
            ], 401);
        }
        $log_data = [
            'msisdn' => $check_phone,
            'amount' => $request->tamount,
            'user_id' => $merchant->id,
            'merchant_balance' => $merchant->balance,
            'session_id' => $extRefId,
            'status' => $topup_result_arr,
            'network' => 'n.a'
        ];
        $desc = [
            'title' =>'customer top up by Merchant ID ' . $merchant->id,
            'data' => $log_data,
            'type' => 'merchant',
        ];

        $activity = new ActivityLog;
        $activity->user_id = $merchant->id;
        $activity->user_type = 'merchant';
        $activity->description = json_encode($desc);
        $activity->save();


        if ($topup_result_arr['code'] == 1) {
            
            $merchant_update = Models\Merchant::find($merchant->id);
            $merchant_update->balance = $prev_balance - $request->amount;
            $merchant_update->save();
            $desc = [
                'title' =>'Successful customer top up by Merchant ID ' . $merchant->id,
                'data' => ['previous_balance' => $merchant->balance, 'current_balance' => $merchant->balance - $request->amount],
                'type' => 'merchant',
            ];
            #update transactions
            $transaction = Models\Transaction::find($transaction_id);
            $transaction->status = $topup_result_arr['message'];
            $transaction->save();

            $activity = new ActivityLog;
            $activity->user_id = $merchant->id;
            $activity->user_type = 'merchant';
            $activity->description = json_encode($desc);
            $activity->save();
            return response()->json([
                'success' => true,
                'message' => 'Top Up Successfully processed!'
            ], 200);
        }
        
    }


    public function customerTopupStore(Request $request){
        $request->validate([
            'phone_number' => 'required|string', 
            'amount'       => 'required|numeric|min:1',
            'merchant_id'  => 'required|integer|exists:merchants,id' 
        ]);


        $phone_number = preg_replace('/\s+/', '', $request->phone_number);
        $check_phone = $this->validatePhoneNumber($phone_number);


        if (!$check_phone) {
            return response()->json(['success' => false, 'message' => 'Invalid phone number!'], 422);
        }

        $merchant = Models\Merchant::find($request->merchant_id);
        $country_prefix = substr($check_phone, 0, 3);
        $country = '';
        switch ($country_prefix) {
            case '265':
                $country = 'MALAWI';
                break;
            case '260':
                $country = 'ZAMBIA';
                break;
            
            default:
                $country = '';
                break;
        }
        if ($merchant->country !== $country) {
            // find out from team 
             return response()->json(['success' => false, 'message' => 'Country not allowed!'], 400);
        }
        $extRefId = uniqid() . '-' . date('YmdHis');
        $topup_result_arr = null;
        
        try {
            $topup_result = DB::transaction(function () use ($request, $check_phone, $extRefId, &$topup_result_arr) {
                
             
                $merchant = Merchant::lockForUpdate()->find($request->merchant_id);

                if ($merchant->balance < $request->amount) {
                    throw new \Exception('Insufficient balance!', 400);
                }


                $prev_balance = $merchant->balance;
                $merchant->balance -= $request->amount;
                $merchant->save();


                $transaction = Transaction::create([
                    'msisdn'      => $check_phone, 
                    'amount'      => $request->amount,
                    'merchant_id' => $merchant->id, 
                    'session_id'  => $extRefId,
                    'status'      => 'PENDING'
                ]);


                $click_params = [
                    "msisdn"   => $check_phone,
                    "amount"   => $request->amount,
                    "extRefId" => $extRefId
                ];
                Log::info('ClickADP Request:', $click_params);

                $api_response = $this->ClickADPHttp($click_params);
                Log::info('ClickADP Response: ' . $api_response);

                $this->sendNtfy($api_response);
                $topup_result_arr = json_decode($api_response, true);

                if (!$api_response || !isset($topup_result_arr['code'])) {
                    throw new \Exception('Top Up Could not be processed at this time. Try again later.', 502);
                }

                if ($topup_result_arr['code'] != 1) {
                    throw new \Exception($topup_result_arr['message'] ?? 'Provider failed to process topup.', 422);
                }

                $transaction->update(['status' => $topup_result_arr['message'] ?? 'SUCCESS']);

                ActivityLog::create([
                    'user_id'     => $merchant->id,
                    'user_type'   => 'merchant',
                    'description' => json_encode([
                        'title' => 'Successful customer top up by Merchant ID ' . $merchant->id,
                        'data'  => [
                            'msisdn'           => $check_phone,
                            'amount'           => $request->amount,
                            'previous_balance' => $prev_balance,
                            'current_balance'  => $merchant->balance,
                            'session_id'       => $extRefId,
                            'status'           => $topup_result_arr,
                            'network'          => 'n.a'
                        ],
                        'type'  => 'merchant',
                    ])
                ]);

                return true;
            });

            return response()->json([
                'success' => true,
                'message' => 'Top Up Successfully processed!'
            ], 200);

        } catch (\Exception $e) {
            
            Log::error('Topup Failed: ' . $e->getMessage());
            try {
                ActivityLog::create([
                    'user_id'     => $request->merchant_id,
                    'user_type'   => 'merchant',
                    'description' => json_encode([
                        'title' => 'Failed customer top up attempt',
                        'error' => $e->getMessage(),
                        'data'  => ['msisdn' => $check_phone, 'amount' => $request->amount]
                    ])
                ]);

                // $activity = new ActivityLog;
                // $activity->user_id = $merchant->id;
                // $activity->user_type = 'merchant';
                // $activity->description = json_encode($desc);
                // $activity->save();

            } catch (\Exception $logEx) {
                Log::error('Failed to write failure activity log: ' . $logEx->getMessage());
            }

            $code = ($e->getCode() >= 400 && $e->getCode() <= 505) ? $e->getCode() : 500;
            return response()->json([
                'success' => false,
                'message' => $e->getMessage()
            ], $code);
        }
    }


    // Make sure to import your Models and Smsgateway at the top of the file

    public function merchantToDealerRefund(Request $request){   
        $this->validate($request, [
            'transaction_id' => 'required|string',
            'reason'      => 'required|string',
        ]);
        $transaction = Models\MerchantTopUp::with('merchantInfo', 'orgInfo')->where('status', 'success')->where('transaction_id', $request->transaction_id)->first();
        if ($transaction == null) {
                return response()->json([
                    'success' => false,
                    'message' => 'Transaction not found.'
                ], 400);    
        }

  
        $dealer = $transaction->orgInfo;

        if ($transaction->merchantInfo->balance < $request->amount) {
            //ask team to confirm if merchant can have a negative balance
            return response()->json([
                'success' => false,
                'message' => 'Insufficient merchant balance to process this refund.'
            ], 400);
        }

        $merchant_name = $transaction->merchantInfo->fullname;
        $dealer_name = $transaction->orgInfo->name;
        $merchant = Models\Merchant::find($transaction->merchantInfo->id);
        $organisation = Models\Organisation::find($transaction->orgInfo->id);
        try {
            //todo : remove one of organisation or dealer 
            DB::transaction(function () use ($request, $merchant, $organisation, $dealer, $transaction) {
                Models\MerchantToDealerRefund::create([
                    'dealer_id'     => $transaction->org_user_id,
                    'transaction_id'=> $request->transaction_id,
                    'merchant_id'   => $transaction->merchant_id, 
                    'amount'        => $transaction->amount,
                    'dealer_msisdn' => $transaction->orgInfo->phone,
                    'reason'        => $request->reason,
                ]);
                $merchant->decrement('balance', $transaction->amount);
                $organisation->increment('balance', $transaction->amount);

                $desc = [
                    'title' => 'Dealer Refund',
                    'data'  => "Refunded a dealer with an amount of " . $transaction->amount, // Typo fixed
                    'type'  => 'merchant',
                ];

                $activity = new ActivityLog;
                $activity->user_id = $transaction->merchant_id; 
                $activity->user_type = 'merchant';
                $activity->description = json_encode($desc);
                $activity->save();

                $transaction->status = 'refunded';
                $transaction->save();
            });

        } catch (\Exception $e) {
            \Log::error("API : Refund Transaction Failed: " . $e->getMessage());
            return response()->json([
                'success' => false,
                'message' => "API XX Refund Transaction Failed: " . $e->getMessage()
            ], 400);
        }
        $msg = "You have successfully refunded a dealer ($dealer_name) with an amount of $transaction->amount.";
        $dealer_msg = "You have received a refund amount of $transaction->amount from Airtime Merchant ($merchant_name).";
        
        if (env('APP_ENV') !== 'local') {
            try {
                $smsgateway = new Smsgateway; 
                $smsgateway->sendSmsNew($merchant->phone, $msg);
                $smsgateway->sendSmsNew($organisation->phone, $dealer_msg);
            } catch (\Exception $e) {
                \Log::error("API: Failed to send SMS for refund: " . $e->getMessage());
            }
        }

        \Log::info("API :" . $msg);
        \Log::info("API :" . $dealer_msg);
        return response()->json([
            'success' => true,
            'message' => "Dealer Refund successfully processed! "
        ], 200);
    }  

}
