<?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;
use App\Models\QbSync;
use Exception;

class SyncQbData extends Command
{

  protected $signature = 'qbdata:sync';
  protected $ato;
  protected $qbs;
  protected $description = 'Sync QB data';

  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;
    $chunkSize = 10;
    set_time_limit($amountOfTimeSec);

    $qs = config('quickbook.query_size');

    $qbComponents = DB::table('qb_objects')->where('status', 1)->get()->pluck('name')->toArray();

    // get prep sync only
    $workingSync = QbSync::where('status', 1)->whereNull('deleted_at')->whereNotNull('prepared_object')->whereNotNull('prepared_at')
      ->orderBy('id', 'desc')->first();
    if (!$workingSync) return;

    $syncTime = now();

    // use prep data to construt batch op
    $prepData = (array) json_decode(base64_decode($workingSync->prepared_object));

    try {
      DB::beginTransaction();
      foreach ($this->ato as $anAto) {
        // Log::debug("be id: " . $anAto->entity_id);
        $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');
              $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, $chunkSize, 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 (!$this->qbs->doBatchOp2($anAto, $cbra, $workingSync->uuid)) throw new Exception('Batch sync error');
        }
      }
      DB::commit();

      $workingSync->status = 2;
      $workingSync->synced_at = $syncTime;
      $workingSync->save();
    } catch (Exception $ex) {
      DB::rollBack();
      Log::error("error syncing: " . $ex->getMessage());
      $workingSync->status = 0;
      $workingSync->error_object = 'error syncing: ' . $ex->getMessage();
      $workingSync->save();
    }
  }
}
