<?php

namespace App\Jobs;

use App\Models\DetailInvoice;
use App\Models\Invoice;
use App\Models\Settings;
use Carbon\Carbon;
use Exception;
use GuzzleHttp\Client;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldBeUnique;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Event;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log;

class SyncInvoiceData implements ShouldQueue
{
    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;

    public $invoiceData;
    public $syncItems;
    public $checkItems;

    /**
     * Create a new job instance.
     *
     * @return void
     */
    public function __construct($invoiceData, $syncItems, $checkItems)
    {
        $this->invoiceData = $invoiceData;
        $this->syncItems = $syncItems;
        $this->checkItems = $checkItems;
    }


    /**
     * Execute the job.
     */
    public function handle(): void
    {
        Log::info('Starting SyncInvoiceData job', [
            'invoice_no' => $this->invoiceData['no'],
            'sync_items_count' => count($this->syncItems),
            'check_items_count' => count($this->checkItems)
        ]);
        // Fetch necessary data
        $invoice = Invoice::where('no', $this->invoiceData['no'])->first();
        $getsales = DetailInvoice::where('invoice', $this->invoiceData['no'])->first();
        $idsales = $getsales->id_sales ?? null;
        $formattedDate = Carbon::parse($this->invoiceData['date'])->format('Y-m-d');
        $currentDate = Carbon::now()->format('Y-m-d');
        $user = Auth::user();
        $setting = Settings::where('wh_code', $user->whs_code)->first();
        $url = $setting->url;

        // Determine payment details based on payment method
        [$cash, $card, $cashAccount, $transferAccount] = $this->getPaymentDetails($invoice, $setting);

        // Check if we need to operate in sandbox mode
        if ($invoice->sandbox === 'Y') {
            $syncItemsAfterchange = $this->processItemsInSandbox($setting, $url);
        } else {
            $syncItemsAfterchange = $this->syncItems;
        }

        // Prepare and send data to external API
        $lines = array_map(fn($item) => $item, $syncItemsAfterchange);
        $commentCode = "{$user->whs_code}/{$this->invoiceData['no']}/{$user->name}";

        $data = [
            "CardCode" => $setting->cardcode,
            "CntctCode" => "0",
            "NumAtCard" => "0",
            "DocDate" => $formattedDate,
            "DocDueDate" => $formattedDate,
            "TaxDate" => $formattedDate,
            "SlpCode" => $idsales,
            "Comments" => $commentCode,
            "BPLId" => $setting->bpl_id,
            "CashAccount" => $cashAccount,
            "CashSum" => $cash,
            "TransferAccount" => $transferAccount,
            "TransferSum" => $card,
            "TransferDate" => $currentDate,
            "DocType" => "C",
            "Lines" => $lines,
        ];

        $this->sendToExternalApi($data, $setting->url, $invoice);
    }

    // Helper method to handle payment details based on payment type
    private function getPaymentDetails($invoice, $setting)
    {
        $cash = $card = 0;
        $cashAccount = $transferAccount = '';

        if ($invoice->payment === "Multi") {
            $note = json_decode($invoice['note'], true);
            $cash = $note['cash'];
            $card = $note['transfer'];
            $cashAccount = $setting->cashacc;
            $transferAccount = $setting->cardacc;
        } elseif ($invoice->payment === "Card") {
            $note = json_decode($invoice['note'], true);
            $card = $note['transfer'];
            $transferAccount = $setting->cardacc;
        } elseif ($invoice->payment === "Cash") {
            $cash = $invoice->must_paid;
            $cashAccount = $setting->cashacc;
        } elseif ($invoice->payment === "Qris") {
            $card = $invoice->must_paid;
            $transferAccount = $setting->cardacc;
        }

        return [$cash, $card, $cashAccount, $transferAccount];
    }

    // Helper method for sandbox item processing
    private function processItemsInSandbox($setting, $url)
    {
        $syncItemsAfterchange = [];

        foreach ($this->checkItems as $item) {
            $itemCode = $this->getItemCodeFromApi($url, $item['ItemCode'], $item['CodeBars']);
            if ($itemCode) {
                $this->updateItemData($itemCode, $item);
            }
        }

        $cartData = DetailInvoice::where('invoice', $this->invoiceData['no'])->get();
        foreach ($cartData as $cart) {
            $syncItemsAfterchange[] = [
                'ItemCode' => $cart->code,
                'Quantity' => $cart->qty,
                'UnitPrice' => $cart->nprice,
                'LineTotal' => $cart->total_price,
                'WhsCode' => $setting->wh_code,
                'Cost1' => $setting->cost1,
                'Cost2' => $setting->cost2,
                'Cost3' => $setting->cost3,
                'Cost4' => $setting->cost4,
                'Cost5' => $setting->cost5,
            ];
        }

        return $syncItemsAfterchange;
    }

    // Helper method for sending data to external API
    private function sendToExternalApi($data, $url, $invoice)
    {
        try {
            $client = new Client();
            $response = $client->post($url . '/api/addarinvoice', [
                'headers' => ['Content-Type' => 'application/json'],
                'json' => $data,
            ]);

            $responseBody = $response->getBody()->getContents();
            $responseData = json_decode($responseBody, true);

            if ($responseData['ErrorCode'] === 0) {
                $invoice->sync = 'Y';
                $invoice->sandbox = 'N';
                DetailInvoice::where('invoice', $this->invoiceData['no'])->update(['sandbox' => 'N']);
                $invoice->save();

                // sleep(3); // Delay in seconds

                
                session()->put('successSync', [
                    'invoice_no' => $invoice->no,
                    'response' => $responseData
                ]);
            } else {
                // Handle error code if needed
            }
        } catch (Exception $e) {
            // Log error or handle it
        }
    }

    // Helper method to fetch item code from API and process accordingly
    private function getItemCodeFromApi($url, $itemCode, $codeBars)
    {
        $response = Http::post($url . '/api/search', [
            "Select" => "\"ItemCode\"",
            "From" => "OITM",
            "Where" => "\"ItemCode\"='" . $itemCode . "';",
        ]);

        $jsonData = $response->json();
        if (!empty($jsonData[0]['ItemCode'])) {
            return $itemCode;
        }

        $response2 = Http::post($url . '/api/search', [
            "Select" => "\"CodeBars\", \"ItemCode\", \"ItemName\"",
            "From" => "OITM",
            "Where" => "\"CodeBars\"='" . $codeBars . "';",
        ]);

        $jsonData2 = $response2->json();
        return !empty($jsonData2[0]['CodeBars']) ? $jsonData2[0]['ItemCode'] : null;
    }

    // Helper method to update item data
    private function updateItemData($itemCode, $item)
    {
        $existingItem = DB::table('Luv2_item')->where('barcode', $item['CodeBars'])->get();

        if ($existingItem->count() > 1) {
            $existItem = DB::table('Luv2_item')
                ->where('barcode', $item['CodeBars'])
                ->whereNot('code', $itemCode)
                ->first();

            DB::table('Luv2_item')
                ->where('code', $itemCode)
                ->where('barcode', $item['CodeBars'])
                ->delete();

            DB::table('Luv2_item_pricelist')
                ->where('item_code', $itemCode)
                ->delete();

            DB::table('Luv2_detailinvoice')
                ->where('invoice', $this->invoiceData['no'])
                ->where('code', $itemCode)
                ->update(['code' => $existItem->code, 'name' => $existItem->name]);
        }
    }
}
