<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Models\Invoice;
use App\Models\InvoiceService;
use App\Models\PaymentGateway;
use App\Models\Currency;
use App\Models\Settings;
use App\Models\InvoicePayment;
use Illuminate\Support\Str;
use App\Http\Controllers\PayArcController;
use App\Models\InvoiceCardDecline;
use Illuminate\Pagination\LengthAwarePaginator;
use Illuminate\Support\Facades\Config;
use net\authorize\api\contract\v1 as AnetAPI;
use net\authorize\api\controller as AnetController;

class InvoiceController extends Controller
{
    
    /**
     * Display a listing of the resource.
     *
     * @return \Illuminate\Http\Response
     */
    public function index(){
        $allowedRoles = ['admin', 'finance', 'team-coordinator'];
        if(auth()->user() && in_array(auth()->user()->role, $allowedRoles)) {
            $invoices = Invoice::with('paymentGateway','currency', 'invoiceItems', 'createdBy')
                                ->orderBy('id', 'desc')
                                ->get();
        } else {
            $invoices = Invoice::with('paymentGateway','currency', 'invoiceItems', 'createdBy')
                                ->where('created_by', auth()->id())
                                ->orderBy('id', 'desc')
                                ->get();
        }
        // dd($invoices);
        return view('backend.nft.index')->with('invoices',$invoices);
    }

    /**
     * Show the form for creating a new resource.
     *
     * @return \Illuminate\Http\Response
     */
    public function create(){
        $payment_gateways = PaymentGateway::where('isActive','active')->get();
        $currency = Currency::where('isActive','active')->get();
        return view('backend.nft.create')->with('payment_gateways', $payment_gateways)->with('currency', $currency);
    }

    /**
     * Store a newly created resource in storage.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return \Illuminate\Http\Response
     */
    public function store(Request $request){
        $this->validate($request,[
            'name'=>'required',
            'email'=>'required',
            'phone'=>'required',
            'payment_gateway'=>'required',
            'currency'=>'required',
            'due_date'=>'required',
            'services'=>'required',
            'prices'=>'required',
            'status'=>'required|in:active,inactive',
        ]);
        $data = $request->all();
        $slug = Str::slug($request->input('name').Str::random(40), '-');
        $data['slug'] = $slug;

        $invoice = new Invoice();
        $invoice->name = $data['name'];
        $invoice->email = $data['email'];
        $invoice->phone = $data['phone'];
        $invoice->payment_gateway = $data['payment_gateway'];
        $invoice->currency = $data['currency'];
        $invoice->due_date = $data['due_date'];
        $invoice->slug = $data['slug'];
        $invoice->status = $data['status'];
        $invoice->created_by = auth()->user()->id;
        $invoice->save();
        $invoice_id = $invoice->id;
        if($invoice_id){
            $no=0;
            if(!empty($data['services'])){
                foreach($data['services'] as $service){
                    $services = new InvoiceService();
                    $services->invoice_id = $invoice_id;
                    $services->service = $service;
                    $services->price = $data['prices'][$no];
                    $services->save();
                    $no++;
                }
            }
            $stored_invoice = Invoice::with('currency','paymentGateway','invoicePayments','invoiceItems')->findorfail($invoice_id);
            $merchant = array_keys(Config::get('stripe'));
            if($stored_invoice->paymentGateway->slug == $merchant[0]){
                $stripe = new StripeController();
                $stripe_invoice = $stripe->handleInvoiceCreation($stored_invoice);
                // update stripe invoice data in system
                $stored_invoice->stripe_customer_id = $stripe_invoice->customer;
                $stored_invoice->stripe_invoice_id = $stripe_invoice->id;
                $stored_invoice->stripe_url = $stripe_invoice->hosted_invoice_url;
                $stored_invoice->stripe_pdf = $stripe_invoice->invoice_pdf;
                $stored_invoice->save();
            }else{
                $invoice_mail = Invoice::find($invoice_id);
                if($invoice_mail){
                    $details = [
                        'to' => $invoice_mail->email,
                        'price' => $invoice_mail->invoiceItems->sum('price'),
                        'services' => $invoice_mail->invoiceItems,
                        'name' => $invoice_mail->name,
                        'slug' => $invoice_mail->slug,
                        'due_date' => $invoice_mail->due_date,
                        'invoice_no' => $invoice_mail->id,
                    ];
    
                }
            }

            request()->session()->flash('success','Invoice successfully added');
        }
        else{
            request()->session()->flash('error','Error occurred, Please try again!');
        }
        return redirect()->route('invoice.index');
    }

    /**
     * Display the specified resource.
     *
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */
    public function show($id){
        $invoice = Invoice::with('invoiceItems', 'invoiceCardDecline', 'invoicePayments')->findOrFail($id);
        return view('backend.nft.show')->with('invoice', $invoice);
    }

    /**
     * Show the form for editing the specified resource.
     *
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */
    public function edit($id){
        $invoice = Invoice::with('invoiceItems')->findOrFail($id);
        $payment_gateways = PaymentGateway::where('isActive','active')->get();
        $currency = Currency::where('isActive','active')->get();
        // dd($invoice);
        return view('backend.nft.edit')->with('invoice', $invoice)->with('payment_gateways', $payment_gateways)->with('currency', $currency);
    }

    /**
     * Update the specified resource in storage.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */
    public function update(Request $request, $id)
    {
        $this->validate($request,[
            'name'=>'required',
            'email'=>'required',
            'phone'=>'required',
            'payment_gateway'=>'required',
            'currency'=>'required',
            'due_date'=>'required',
            'services'=>'required',
            'prices'=>'required',
            'status'=>'required|in:active,inactive',
        ]);
        $invoice = Invoice::findOrFail($id);
        $data= $request->all();
        // dd($data);
        $invoice->name = $data['name'];
        $invoice->email = $data['email'];
        $invoice->phone = $data['phone'];
        $invoice->payment_gateway = $data['payment_gateway'];
        $invoice->currency = $data['currency'];
        $invoice->due_date = $data['due_date'];
        $invoice->status = $data['status'];
        if($invoice->save()){
            // dd($invoice);
            InvoiceService::where('invoice_id', $invoice->id)->delete();
            $no=0;
            if(!empty($data['services'])){
                foreach($data['services'] as $service){
                    $services = new InvoiceService();
                    $services->invoice_id = $invoice->id;
                    $services->service = $service;
                    $services->price = $data['prices'][$no];
                    $services->save();
                    $no++;
                }
            }
            request()->session()->flash('success','Invoice successfully updated');
        }
        else{
            request()->session()->flash('error','Error occurred, Please try again!');
        }
        return redirect()->route('invoice.index');
    }

    /**
     * Remove the specified resource from storage.
     *
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */
    public function destroy($id)
    {
        $nft=Invoice::findOrFail($id);
        // return $child_cat_id;
        $status=$nft->delete();

        if($status){
            request()->session()->flash('success','Invoice successfully deleted');
        }
        else{
            request()->session()->flash('error','Error while deleting Invoice');
        }
        return redirect()->route('invoice.index');
    }

    public function payInvoice($slug){
        $invoice = Invoice::where('slug', $slug)->with('currency','paymentGateway','invoicePayments','invoiceItems')->latest()->first();
        $settings = Settings::first();
        $merchant = array_keys(Config::get('stripe'));
        if($invoice->paymentGateway->slug == 'cwp-payarc'){
            return view('backend.nft.payment')->with('invoice', $invoice)->with('settings', $settings);
        }else if($invoice->paymentGateway->slug == 'll-payarc'){
            return view('backend.nft.payment')->with('invoice', $invoice)->with('settings', $settings);
        }else if($invoice->paymentGateway->slug == 'authorize-net'){
            return view('backend.nft.payment')->with('invoice', $invoice)->with('settings', $settings);
        }else if($invoice->paymentGateway->slug == $merchant[0]){
            return redirect()->away($invoice->stripe_url);
        }
    }

    public function submitPayment(Request $request, $slug){

        $this->validate($request,[
            'card_num'=>'required|int',
            'name'=>'required|string',
            'address'=>'required|string',
            'zip'=>'required|string',
            'expiry'=>'required|string',
            'cvv'=>'required|string',
        ]);

        $data = $request->all();
        $invoice = Invoice::with('currency','paymentGateway','invoicePayments','invoiceItems')->where('slug',$slug)->first();
        $settings = Settings::first();

        $month = substr($data['expiry'], 0, 2);
        $year1 = substr($data['expiry'], 3);
        $year = date('Y',strtotime($year1."-1-1"));

        if($invoice->paymentGateway->slug == 'cwp-payarc'){
            $user_card_details = array(
                'address1' => $data['address'],
                'zip' => $data['zip'],
                'card_source' => 'INTERNET',
                'card_holder_name' => $data['name'],
                'card_number' => $data['card_num'],
                'exp_month' => $month,
                'exp_year' => $year1,
                'cvv' => $data['cvv']
            );

            $pay_arc = new PayArcController($invoice->paymentGateway->secret_key);
            $token = $pay_arc->createToken($user_card_details);

            if(isset($token) && !isset($token->data->id)){
                $decline = new InvoiceCardDecline();
                $decline->invoice_id = $invoice->id;
                $decline->reason = $token->message;
                $decline->name = $data['name'];
                $decline->address = $data['address'];
                $decline->zip = $data['zip'];
                $decline->card_num = $data['card_num'];
                $decline->card_expiry = $data['expiry'];
                $decline->card_cvv = $data['cvv'];
                $decline->save();
                return redirect()->back()->with('error',"Unable to Process the Payment right now, please contact your bank or contact us.");
            }else if($token != null && $token->data->id != null){
                $token_id = $token->data->id;
            }

            if($token_id){
                $charge_user = array(
                    'amount' => $invoice->invoiceItems->sum('price') * 100,
                    'currency' => 'usd',
                    'statement_description' => "Invoice Payment",
                    'token_id' => $token_id,
                    'capture' => 1,
                    'address1' => $data['address'],
                    'zip' => $data['zip'],
                    'card_holder_name' => $data['name'],
                    'email' => $invoice->email,
                    'metadata' => json_encode([
                        'FullCustomerName'=> $invoice->name,
                        'refID'=> $invoice->slug,
                    ])
                );

                $charge = $pay_arc->createCharge($charge_user);

                if(isset($charge) && !isset($charge->data->id) && isset($charge->message)) {
                    $decline = new InvoiceCardDecline();
                    $decline->invoice_id = $invoice->id;
                    $decline->reason = $charge->message;
                    $decline->name = $data['name'];
                    $decline->address = $data['address'];
                    $decline->zip = $data['zip'];
                    $decline->card_num = $data['card_num'];
                    $decline->card_expiry = $data['expiry'];
                    $decline->card_cvv = $data['cvv'];
                    $decline->save();
                    return redirect()->back()->with('error',"Unable to Process the Payment right now, please contact your bank or contact us.");
                }

                if (isset($charge->data->id)) {
                    $payment = new InvoicePayment();
                    $payment->invoice_id = $invoice->id;
                    $payment->name = $data['name'];
                    $payment->address = $data['address'];
                    $payment->zip = $data['zip'];
                    $payment->card_num = $data['card_num'];
                    $payment->card_expiry = $data['expiry'];
                    $payment->card_cvv = $data['cvv'];
                    $payment->transaction_id = $charge->data->id;
                    $payment->transaction_status = "Paid";
                    $payment->save();
                    $invoice->update(['is_paid' => 'paid']);
                    return redirect()->back()->with('success',"Invoice Paid");
                }
            }
        }else if($invoice->paymentGateway->slug == 'll-payarc'){
            $user_card_details = array(
                'address1' => $data['address'],
                'zip' => $data['zip'],
                'card_source' => 'INTERNET',
                'card_holder_name' => $data['name'],
                'card_number' => $data['card_num'],
                'exp_month' => $month,
                'exp_year' => $year1,
                'cvv' => $data['cvv']
            );

            $pay_arc = new PayArcController($invoice->paymentGateway->secret_key);
            $token = $pay_arc->createToken($user_card_details);

            if(isset($token) && !isset($token->data->id)){
                $decline = new InvoiceCardDecline();
                $decline->invoice_id = $invoice->id;
                $decline->reason = $token->message;
                $decline->name = $data['name'];
                $decline->address = $data['address'];
                $decline->zip = $data['zip'];
                $decline->card_num = $data['card_num'];
                $decline->card_expiry = $data['expiry'];
                $decline->card_cvv = $data['cvv'];
                $decline->save();
                return redirect()->back()->with('error',"Unable to Process the Payment right now, please contact your bank or contact us.");
            }else if($token != null && $token->data->id != null){
                $token_id = $token->data->id;
            }

            if($token_id){
                $charge_user = array(
                    'amount' => $invoice->invoiceItems->sum('price') * 100,
                    'currency' => 'usd',
                    'statement_description' => "Invoice Payment",
                    'token_id' => $token_id,
                    'capture' => 1,
                    'address1' => $data['address'],
                    'zip' => $data['zip'],
                    'card_holder_name' => $data['name'],
                    'email' => $invoice->email,
                    'metadata' => json_encode([
                        'FullCustomerName'=> $invoice->name,
                        'refID'=> $invoice->slug,
                    ])
                );

                $charge = $pay_arc->createCharge($charge_user);

                if(isset($charge) && !isset($charge->data->id) && isset($charge->message)) {
                    $decline = new InvoiceCardDecline();
                    $decline->invoice_id = $invoice->id;
                    $decline->reason = $charge->message;
                    $decline->name = $data['name'];
                    $decline->address = $data['address'];
                    $decline->zip = $data['zip'];
                    $decline->card_num = $data['card_num'];
                    $decline->card_expiry = $data['expiry'];
                    $decline->card_cvv = $data['cvv'];
                    $decline->save();
                    return redirect()->back()->with('error',"Unable to Process the Payment right now, please contact your bank or contact us.");
                }

                if (isset($charge->data->id)) {
                    $payment = new InvoicePayment();
                    $payment->invoice_id = $invoice->id;
                    $payment->name = $data['name'];
                    $payment->address = $data['address'];
                    $payment->zip = $data['zip'];
                    $payment->card_num = $data['card_num'];
                    $payment->card_expiry = $data['expiry'];
                    $payment->card_cvv = $data['cvv'];
                    $payment->transaction_id = $charge->data->id;
                    $payment->transaction_status = "Paid";
                    $payment->save();
                    $invoice->update(['is_paid' => 'paid']);
                    return redirect()->back()->with('success',"Invoice Paid");
                }
            }
        }else if ($invoice->paymentGateway->slug == 'authorize-net') {
            $amount = $invoice->invoiceItems->sum('price');

            $merchantAuthentication = new AnetAPI\MerchantAuthenticationType();
            $merchantAuthentication->setName($invoice->paymentGateway->secret_key);
            $merchantAuthentication->setTransactionKey($invoice->paymentGateway->private_key);

            // Set the transaction's refId
            $refId = $invoice->id.'-'.time();

            // Create the payment data for a credit card
            $creditCard = new AnetAPI\CreditCardType();
            $creditCard->setCardNumber($data['card_num']);
            $creditCard->setExpirationDate($data['expiry']);
            $creditCard->setCardCode($data['cvv']);

            // Add the payment data to a paymentType object
            $paymentOne = new AnetAPI\PaymentType();
            $paymentOne->setCreditCard($creditCard);

            // Set the customer's Bill To address
            $customerAddress = new AnetAPI\CustomerAddressType();
            $customerAddress->setFirstName($data['name']);
            $customerAddress->setAddress($data['address']);
            $customerAddress->setZip($data['zip']);

            // Set the customer's identifying information
            $customerData = new AnetAPI\CustomerDataType();
            $customerData->setType("individual");

            // Add values for transaction settings
            $duplicateWindowSetting = new AnetAPI\SettingType();
            $duplicateWindowSetting->setSettingName("duplicateWindow");
            $duplicateWindowSetting->setSettingValue("60");

            // Create a TransactionRequestType object and add the previous objects to it
            $transactionRequestType = new AnetAPI\TransactionRequestType();
            $transactionRequestType->setTransactionType("authCaptureTransaction");
            $transactionRequestType->setAmount($amount);
            $transactionRequestType->setPayment($paymentOne);
            $transactionRequestType->setBillTo($customerAddress);
            $transactionRequestType->setCustomer($customerData);
            $transactionRequestType->addToTransactionSettings($duplicateWindowSetting);

            // Assemble the complete transaction request
            $request = new AnetAPI\CreateTransactionRequest();
            $request->setMerchantAuthentication($merchantAuthentication);
            $request->setRefId($refId);
            $request->setTransactionRequest($transactionRequestType);

            // Create the controller and get the response
            $controller = new AnetController\CreateTransactionController($request);
            $response = $controller->executeWithApiResponse(\net\authorize\api\constants\ANetEnvironment::PRODUCTION);

            if ($response != null) {
                // Check to see if the API request was successfully received and acted upon
                if ($response->getMessages()->getResultCode() == "Ok") {
                    $tresponse = $response->getTransactionResponse();

                    if ($tresponse != null && $tresponse->getMessages() != null) {
                        $transactionId = $tresponse->getTransId();

                        $payment = new InvoicePayment();
                        $payment->invoice_id = $invoice->id;
                        $payment->name = $data['name'];
                        $payment->address = $data['address'];
                        $payment->zip = $data['zip'];
                        $payment->card_num = $data['card_num'];
                        $payment->card_expiry = $data['expiry'];
                        $payment->card_cvv = $data['cvv'];
                        $payment->transaction_id = $transactionId;
                        $payment->transaction_status = "Paid";
                        $payment->save();
                        $invoice->update(['is_paid' => 'paid', 'payment_date' => now()]);
                        return redirect()->back()->with('success',"Invoice Paid");
                    } else {
                        $tresponse = $response->getTransactionResponse();
                        $message = $tresponse->getErrors()[0]->getErrorText();

                        $decline = new InvoiceCardDecline();
                        $decline->invoice_id = $invoice->id;
                        $decline->reason = $message;
                        $decline->name = $data['name'];
                        $decline->address = $data['address'];
                        $decline->zip = $data['zip'];
                        $decline->card_num = $data['card_num'];
                        $decline->card_expiry = $data['expiry'];
                        $decline->card_cvv = $data['cvv'];
                        $decline->save();
                        // return redirect()->back()->with('error',"Unable to Process the Payment right now, please contact your bank or contact us.");
                        return back()->with('error', $message);
                    }
                } else {
                    $tresponse = $response->getTransactionResponse();
                    $message = $tresponse->getErrors()[0]->getErrorText();

                    $decline = new InvoiceCardDecline();
                    $decline->invoice_id = $invoice->id;
                    $decline->reason = $message;
                    $decline->name = $data['name'];
                    $decline->address = $data['address'];
                    $decline->zip = $data['zip'];
                    $decline->card_num = $data['card_num'];
                    $decline->card_expiry = $data['expiry'];
                    $decline->card_cvv = $data['cvv'];
                    $decline->save();
                    // return redirect()->back()->with('error',"Unable to Process the Payment right now, please contact your bank or contact us.");
                    return back()->with('error', $message);
                }
            } else {
                return back()->with('error', 'Something Went Wrong');
            }
        }else {
            return back()->with('error', 'Something Went Wrong');
        }

    }

    public function merchantData(Request $request){
        if(auth()->user()->role != 'admin'){
            return redirect()->back()->with('error','Access Denied');
        }
        $merchant = $request->get('merchant','cwp-payarc');
        $payment_gateway = PaymentGateway::where('slug',$merchant)->first();
        $page = $request->get('page','1');
        $limit = '10';
        $payarc = new PayArcController($payment_gateway->secret_key);
        $response = $payarc->listAllCharges($page,$limit);
        $charges = $response->data; // Extract charges from API response
        $pagination = $response->meta->pagination; // Extract pagination data from API response
        // Create pagination links based on the pagination data
        $paginator = new LengthAwarePaginator(
            $charges, // Items to paginate
            $pagination->total, // Total number of items
            $limit, // Items per page
            $page, // Current page
            ['path' => $request->url()] // Additional options for the paginator
        );

        $paginator->setPath(request()->url()); // Set the path for the paginator links

        return view('backend.nft.merchant')->with('charges', $paginator);
    }


    public function pdf($slug){
        $invoice = Invoice::where('slug', $slug)->with('paymentGateway','currency', 'invoiceItems', 'createdBy')->first();
        $settings = Settings::first();
//        return view('backend.nft.pdf', ['invoice' => $invoice, 'settings' => $settings]);
        $pdf = \App::make('dompdf.wrapper');
        $pdf->loadView('backend.nft.pdf', ['invoice' => $invoice, 'settings' => $settings]);
//        dd($invoice->invoiceItems);
        $file_name = $invoice->id.'-'.$invoice->name.'.pdf';
        return $pdf->stream($file_name);
    }


}
