<?php

namespace App\Console\Commands;

use Illuminate\Console\Command;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;
use App\Services\QuickbookService;
use Illuminate\Support\Facades\Crypt;

class SyncQbData extends Command
{
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'qbdata:sync';
    protected $ato;
    protected $qbs;
    // protected $querySize = 1000;

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = 'Sync QB data';

    /**
     * Create a new command instance.
     *
     * @return void
     */
    public function __construct()
    {
        parent::__construct();
        $this->qbs = new QuickbookService();
        $this->ato = $this->qbs->getStoredAto();
    }

    /**
     * Execute the console command.
     * - invoice
     * - invoice items
     * - payments
     * - payment methods
     * - customers
     *
     * @return int
     */
    public function handle()
    {
        $amountOfTimeSec = 1800;
        set_time_limit($amountOfTimeSec);
        $qs = config('quickbook.query_size');
        // Log::debug("query size: " . $qs);
        // if(count($this->ato) === 0) Log::error('no valid ato');
        // $qbComponents = array('Payment', 'PaymentMethod', 'Customer','Item', 'Invoice', 'CreditMemo');
        $qbComponents = DB::table('qb_objects')->where('status', 1)->get()->pluck('name')->toArray();
        // get prep sync only
        $workingSync = DB::table('qb_syncs')->where([
            ['status', '=', 1]
        ])->whereNull('deleted_at')->whereNotNull('prepared_object')->whereNotNull('prepared_at')->orderBy('id', 'desc')->first();
        if(!$workingSync) return 0;
        $syncTime = now();

        // use prep data to construt batch op
        $prepData = (array) json_decode(base64_decode($workingSync->prepared_object));
        // if(count($prepData) > 0) Log::debug('pd: ' . count($prepData));
        Log::debug("prep data: " . print_r($prepData, true));

        try{
            DB::beginTransaction();
            foreach($this->ato as $anAto){
                Log::debug("be id: " . $anAto->entity_id);
                // Log::debug(print_r($anAto->entity_id, true));
                // batch per business entity
                $batchRequestStrArr = [];
    
                foreach($qbComponents as $qbc){
                    $s = $prepData[$anAto->entity_id]->$qbc;
                    // Log::debug("size $s");
                    $iteration = (floor(intval($s) / $qs)) + 1;
                    // Log::debug("iteration $iteration");
                    $start = 1;
                    $seq = 1;
                    do{
                        if($workingSync->cut_off_time){
                            $wscot = date_format(date_create($workingSync->cut_off_time),'c');
                            // Log::debug('sync: ' . $wscot);
                            $tStr = "select * from $qbc where MetaData.CreateTime > '$wscot' startPosition $start maxResults $qs";
                        }else{
                            $tStr = "select * from $qbc startPosition $start maxResults $qs";
                        }
                        // array_push($batchRequestStrArr, $tStr);
                        $batchRequestStrArr[$qbc . '-' . $seq] = $tStr;
                        $start += $qs;
                        $seq++;
                    }while($start < (($iteration * $qs) + 1));
    
                    // execute
                    // Log::debug(print_r($batchRequestStrArr, true));
                }
                Log::debug('bqsa: ' . count($batchRequestStrArr));
                Log::debug(print_r($batchRequestStrArr, true));
    
                // chunking
                $chunkedBatchRequestArr = array_chunk($batchRequestStrArr, 20, true); // working for all but invoice - timout
                // $chunkedBatchRequestArr = array_chunk($batchRequestStrArr, 30, true); // working for all but invoice - timout
                Log::debug("chunked count: " . count($chunkedBatchRequestArr));
                foreach($chunkedBatchRequestArr as $cbra){
                    Log::debug('chunk size: ' . count($cbra));
                    // Log::debug(print_r($cbra, true));
                    // Log::debug("uuid: " . $workingSync->uuid);
                    if(!$this->qbs->doBatchOp($anAto, $cbra, $workingSync->uuid)) break; 
                }
    
                // if one op failed, cancel the whole sync
                // if(!$this->qbs->doBatchOp($anAto, $batchRequestStrArr, $workingSync->uuid)) break;
            }
            DB::commit();
    
            DB::table('qb_syncs')->where([
                ['status','=',1], ['uuid','=',$workingSync->uuid]
            ])->whereNull('deleted_at')->update([
                'status' => 2, 'synced_at' => $syncTime
            ]);
        }catch(Exception $ex){
            DB::rollBack();
            DB::table('qb_syncs')->where([
                ['status','=',1], ['uuid','=',$workingSync->uuid]
            ])->whereNull('deleted_at')->update([
                'status' => 0, 'error_object' => 'error syncing'
            ]);
        }
        


        // only get open invoices or those created 3 years ago
        // if($lastSync){
        //     // get changes
        // }else{
        //     // do batch data retrievel
        //     Log::debug('syncing data for the first time...');
        //     $syncUuid = Str::uuid();
        //     $syncId = DB::table('qb_syncs')->insertGetId([
        //         'uuid' => $syncUuid, 'created_at' => now()
        //     ]);
        //     foreach($this->ato as $anAto){
        //         Log::debug(print_r($anAto, true));
        //         $ui = Str::uuid();

        //         // prep
        //         $prepData = $this->qbs->prepBatchOp(Crypt::decrypt($anAto->token_object), $ui);
        //         Log::debug(print_r($prepData, true));
        //         // i am accessing Quickbooks data using quickbooks/v3-php-sdk package. using batch request, how to get number of records from Customer, Invoice and Payment

        //         // fetching
        //         // $syncData = $this->qbs->getBatchData(Crypt::decrypt($anAto->token_object), 'all', $ui, 1, 100);
        //         // Log::debug(print_r($syncData, true));
        //     }
        // }
    }
}
