<?php

namespace App\Http\Controllers;

use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
use Illuminate\Foundation\Bus\DispatchesJobs;
use Illuminate\Foundation\Validation\ValidatesRequests;
use Illuminate\Routing\Controller as BaseController;
use Illuminate\Http\Request;
use App\Models\FinancialYear;
use App\Models\User;
use App\Models\Account;
use App\Models\AccountTransaction;
use App\Models\AcReceipt;
use App\Models\OpdBookingDetail;
use App\Models\OpdBookings;
use App\Models\PaymentVoucher;
use App\Models\SaleInvoice;
use App\Models\SaleInvoiceDetail;
use App\Models\ProductTestPackage;
use App\Models\Purchase\PurchaseInvoiceDetails;
use App\Models\Purchase\PurchaseOthersTransaction;
use App\Models\TaskStatus;
use App\Models\SaleInvoiceSubDetails;
use App\Models\SaleOthersTransaction;
use App\Models\Sales\SaleReturnDetails;
use App\Models\Sales\SaleReturnOthersTransactions;
use App\Models\Stocks\StockInDetail;
use App\Models\Stocks\StockOutDetail;
use App\Models\VoucherMaster;
use Illuminate\Support\Str;

class Controller extends BaseController
{
    use AuthorizesRequests, DispatchesJobs, ValidatesRequests;

    public function __construct()
    {
        $company         = \Session::get('company_data');
        $company_address = $company['companies_addresses'] ?? [];
        $timezone        = $company_address['time_zone'] ?? 'Asia/Kolkata';
        date_default_timezone_set($timezone);
    }

    public function generateCode($id, $prefix, $postfix = '', $seperator = '', $length = '5', $yearmonth = '')
    {
        $paddedId      = str_pad($id, $length, '0', STR_PAD_LEFT);
        $yearmonth     = $yearmonth != '' ? $yearmonth.$seperator : '';
        $generatedCode = ($postfix == '') ? $prefix . $seperator . $yearmonth . $paddedId : $prefix . $seperator . $paddedId . $seperator . $postfix;

        $account = Account::where('code', $generatedCode)->first();

        if ($account) {
            $id = $id + 1;
            $generatedCode = $this->generateCode($id, $prefix, $postfix, $seperator, $length);
        }

        return $generatedCode;
    }

    public function download(Request $request)
    {
        $url      = $request->filename;
        $response = \Http::get($url);

        if ($response->successful()) {
            $filename = pathinfo(parse_url($url, PHP_URL_PATH), PATHINFO_BASENAME);

            return response()->stream(
                function () use ($response) {
                    echo $response->body();
                },
                200,
                [
                    'Content-Type' => 'application/octet-stream',
                    'Content-Disposition' => 'attachment; filename="' . $filename . '"',
                ]
            );
        }

        return abort(404);
    }

    public function financialyear()
    {
        $user_financial_year_id = \Session::get('user_financial_year_id');

        return $user_financial_year_id;
    }

    public function generateRandomCode($length = 5) {
        $characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
        $code       = '';
        $code2      = '';

        for ($i = 0; $i < $length; $i++) {
            $code  .= $characters[rand(0, strlen($characters) - 1)];
            $code2 .= $characters[rand(0, strlen($characters) - 1)];
        }

        return $code . date('Ymd') . $code2;
    }

    public function generateStringFormate($testString)
    {
        $upper = Str::ucfirst(strtolower(trim($testString)));
        return  $upper;
    }
    protected function cleanAndValidateContactNumbers($phone_no = null)
    {
        if ($phone_no == null) {
            return '';
        } else {
            $phoneNo = str_replace(' ', '', $phone_no);
            $phoneNo = preg_replace("/[^0-9]/", "", $phoneNo);

            $phoneNo = '+' . $phoneNo;
            return $phoneNo;
        }
    }

    public function modulePermissionCheck($module)
    {
        $modulePermissions = \Session::get('modulePermissions') ?? [];

        if(in_array($module, $modulePermissions)) {
            return true;
        }

        return false;
    }

    public function checkPermission($permission)
    {
        $rolePermissions = \Session::get('rolePermissions') ?? [];

        if(in_array($permission, $rolePermissions)) {
            return true;
        }

        return false;
    }


    public function TransactionSummery($invoice_id,$module_code)
    {
       
        $AcReceipt = AcReceipt::select(['id', 'voucher_id'])
        ->with(['accountReceiptReceivedAmount'])
        ->where(['module_code' => $module_code, 'voucher_id' => $invoice_id])
        ->get();

        if($module_code=="OPD_BOOKING")
        {
            $finalTotal    = OpdBookingDetail::where('opd_booking_id',$invoice_id)->sum('amount','price');
            $discountPrice = SaleOthersTransaction::select('price')->where(['sale_invoice_id'=>$invoice_id,'voucher_type'=>$module_code,'account_id'=>67])->first();
            $roundOffPrice = SaleOthersTransaction::select('price')->where(['sale_invoice_id'=>$invoice_id,'voucher_type'=>$module_code,'account_id'=>110])->first();
        }else{
            
            $finalTotal    = SaleInvoiceDetail::where('sale_invoice_id',$invoice_id)->sum('total_amount','price');
            $discountPrice = SaleOthersTransaction::select('price')->where(['sale_invoice_id'=>$invoice_id,'account_id'=>67])->first();
            $roundOffPrice = SaleOthersTransaction::select('price')->where(['sale_invoice_id'=>$invoice_id,'account_id'=>110])->first();
        }

        

         $receivedAmount=0;
        if(isset($AcReceipt))
        {
            foreach($AcReceipt as $rows)
            {
                foreach($rows->accountReceiptReceivedAmount as $row){
                    $receivedAmount+=$row->amount;
                }
            }
        }

        $data=['totalBilling'     => $finalTotal??0,
                'receivedAmount'  => $receivedAmount??0,
                'discountAmount'  => $discountPrice->price??0,
                'roundOffAmount'  => isset($roundOffPrice->price)&&$roundOffPrice->price?sprintf('%0.2f',$roundOffPrice->price):0,
                'dueAmount'       => round($finalTotal-$receivedAmount)
            ];
        return  $data;
    }

    public function companyDateFormate()
    {
        return \Session::get('company_data')['date_format'];
    }

    public function generateTransactionNumber()
    {
     # last voucher count for main Transaction number
     $transaction_voucher_count      = AccountTransaction::select('last_id')->orderBy('created_at', 'DESC')->first();
     $transaction_voucher_master     = VoucherMaster::select('id')
         ->with('voucherSeries')
         ->where('voucher_code', 'TRANSACTION')
         ->where(['status' => 1])
         ->first();
    $last_voucher_count = isset($transaction_voucher_count) && isset($transaction_voucher_count->last_id) ? $transaction_voucher_count->last_id + 1 : (isset($transaction_voucher_master) && $transaction_voucher_master->voucherSeries->start_from + 1 ?? 1);

     $transactions_no = $this->generateCode(
         $last_voucher_count,
         ($transaction_voucher_master->voucherSeries->prefix ?? 'TRN'),
         ($transaction_voucher_master->voucherSeries->postfix ?? ''),
         ($transaction_voucher_master->voucherSeries->separator ?? '-'),
         ($transaction_voucher_master->voucherSeries->length ?? 5)
     );
     $data['transactions_no'] = $transactions_no;
     $data['last_count']      = $last_voucher_count;
     
     return $data;
    }

    public function refreshInvoiceSubDetails($id)
    {
        $sale_invoice_details = SaleInvoiceDetail::where('sale_invoice_id', $id)->get();

        foreach ($sale_invoice_details as $key => $value) {
            $product_test_package = ProductTestPackage::where('product_id', $value['product_id'])->get();

            foreach ($product_test_package as $package) {
                $task_status  = TaskStatus::where('is_default', '1')->first();

                $addedTestPackage = SaleInvoiceSubDetails::updateOrCreate([
                    'sale_invoice_detail_id' => $value->id,
                    'sale_invoice_id'        => $id,
                    'data_referrence_id'     => $package->test_package_id
                ],[
                    'subdetails_remarks'     => '',
                    'referrence_type'        => 'LAB',
                    'status'                 => '0',
                    'task_status_id'         => $task_status->id ?? '',
                    'review_status_id'       => $task_status->id ?? '',
                    'task_created_by_id'     => Auth()->id(),
                ]);
            }
        }

        return true;
    }


    public function ReturnTransactionSummery($invoice_id,$module_code)
    {
       
        $finalTotal    = SaleReturnDetails::where('sale_return_invoice_id',$invoice_id)->sum('total_amount','price');
        $discountPrice = SaleReturnOthersTransactions::select('price')->where(['sale_invoice_id'=>$invoice_id,'account_id'=>67])->first();
        $roundOffPrice = SaleReturnOthersTransactions::select('price')->where(['sale_invoice_id'=>$invoice_id,'account_id'=>110])->first();

         $receivedAmount=0;


        $data=['totalBilling'     => $finalTotal??0,
                'receivedAmount'  => $receivedAmount??0,
                'discountAmount'  => $discountPrice->price??0,
                'roundOffAmount'  => isset($roundOffPrice->price)&&$roundOffPrice->price?sprintf('%0.2f',$roundOffPrice->price):0,
                'dueAmount'       => round($finalTotal-$receivedAmount)
            ];
        return  $data;
    }

    public function PurchaseTransactionSummery($invoice_id,$module_code)
    {
        $paymentVoucher = PaymentVoucher::select(['id', 'voucher_id'])
        ->with(['accountReceiptReceivedAmount'])
        ->where(['module_code' => $module_code, 'voucher_id' => $invoice_id])
        ->get();
       
        $finalTotal    = PurchaseInvoiceDetails::where('purchase_invoice_id',$invoice_id)->sum('total_amount','price');
        $discountPrice = PurchaseOthersTransaction::select('price')->where(['purchase_invoice_id'=>$invoice_id,'account_id'=>67,'voucher_type'=>'PURCHASE'])->first();
        $roundOffPrice = PurchaseOthersTransaction::select('price')->where(['purchase_invoice_id'=>$invoice_id,'account_id'=>110,'voucher_type'=>'PURCHASE'])->first();

        $receivedAmount=0;
        if(isset($paymentVoucher))
        {
            foreach($paymentVoucher as $rows)
            {
                foreach($rows->accountReceiptReceivedAmount as $row){
                    $receivedAmount+=$row->amount;
                }
            }
        }



        $data=['totalBilling'     => round($finalTotal)??0,
                'receivedAmount'  => $receivedAmount??0,
                'discountAmount'  => $discountPrice->price??0,
                'roundOffAmount'  => isset($roundOffPrice->price)&&$roundOffPrice->price?sprintf('%0.2f',$roundOffPrice->price):0,
                'dueAmount'       => round($finalTotal-$receivedAmount)
            ];
        return  $data;
    }

    public function StockTransactionSummery($invoice_id,$module_code)
    {
       if($module_code=="STOCK_IN")
       {
            $finalTotal    = StockInDetail::where('invoice_id',$invoice_id)->sum('total_amount','price');
       }
       elseif($module_code=="STOCK_OUT")
       {
        $finalTotal    = StockOutDetail::where('invoice_id',$invoice_id)->sum('total_amount','price');
       }
        
         $receivedAmount=0;


        $data=['totalBilling'     => $finalTotal??0,
                'receivedAmount'  => $receivedAmount??0,
                'discountAmount'  =>0,
                'roundOffAmount'  => 0,
                'dueAmount'       => round($finalTotal-$receivedAmount)
            ];
        return  $data;
    }

    public function TransactionSummeryBatchWise($invoice_id,$module_code,$bach_id)
    {
        $AcReceipt = AcReceipt::select(['id', 'voucher_id'])
        ->with(['accountReceiptReceivedAmount'])
        ->where(['module_code' => $module_code, 'voucher_id' => $invoice_id])
        ->get();

        if($module_code=="OPD_BOOKING")
        {
            $finalTotal    = OpdBookingDetail::where('opd_booking_id',$invoice_id)->sum('amount','price');
        }else{
            $finalTotal    = SaleInvoiceDetail::where('sale_invoice_id',$invoice_id)->where('batch_id',$bach_id)->sum('total_amount','price');
        }

        $discountPrice = SaleOthersTransaction::select('price')->where(['sale_invoice_id'=>$invoice_id,'account_id'=>67,'sale_invoice_batch_id'=>$bach_id])->first();
        $roundOffPrice = SaleOthersTransaction::select('price')->where(['sale_invoice_id'=>$invoice_id,'account_id'=>110,'sale_invoice_batch_id'=>$bach_id])->first();

         $receivedAmount=0;
        if(isset($AcReceipt))
        {
            foreach($AcReceipt as $rows)
            {
                foreach($rows->accountReceiptReceivedAmount as $row){
                    $receivedAmount+=$row->amount;
                }
            }
        }

        $data=['totalBilling'     => $finalTotal??0,
                'receivedAmount'  => $receivedAmount??0,
                'discountAmount'  => $discountPrice->price??0,
                'roundOffAmount'  => isset($roundOffPrice->price)&&$roundOffPrice->price?sprintf('%0.2f',$roundOffPrice->price):0,
                'dueAmount'       => round($finalTotal-$receivedAmount)
            ];
        return  $data;
    }

    public function get_user_info()
    {
        $account_id = Auth()->user()->account_id;

        if (!$account_id) {
            return false;
        }

        $account = Account::leftjoin('account_types','account_types.id','accounts.account_type_id')
                ->select([
                    'account_types.id',
                    'account_types.type_name',
                    'account_types.type_code'
                ])
                ->where('accounts.id',$account_id)
                ->first();

        if (!$account) {
            return false;
        }

        $data = [
            'type_id'    => $account->id ?? 0,
            'type_name'  => $account->type_name ?? 0,
            'type_code'  => $account->type_code ?? 0,
        ];

        return $data;
    }
}

