<?php

namespace App\Classes\Modules\Imports\ControllersLogic;


use App\Classes\Exceptions\MalformedRequestException;
use App\Classes\General\Abstracts\AbstractControllerLogic;
use App\Classes\Jobs\Commands\V2\ProcessPaymentReportV2CommandJob;
use App\Classes\Jobs\Commands\V2\ProcessSalesInvoiceReportV2CommandJob;
use App\Classes\Modules\KeyValuePairs\Services\CreatesKeyValuePair;
use App\Classes\Modules\KeyValuePairs\Services\UpdatesKeyValuePair;
use App\Classes\Modules\Documents\DataTransferObjects\DocumentObject;
use App\Classes\Modules\KeyValuePairs\DataTransferObjects\KeyValuePairObject;
use App\Classes\Modules\Imports\Services\AutoCountDataImport;
use App\Classes\ValueObjects\Constants\ApprovalStatus;
use App\Classes\ValueObjects\Constants\KVPKey;
use App\Models\Booking;
use App\Models\KeyValuePair;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
use Maatwebsite\Excel\Facades\Excel;

class ImportExcelLogic extends AbstractControllerLogic
{

    /** @var CreatesKeyValuePair */
    private $createsKeyValuePair;

    /** @var UpdatesKeyValuePair */
    private $updatesKeyValuePair;

    /**
     * ImportExcelLogic constructor.
     * @param CreatesKeyValuePair $createsKeyValuePair
     * @param UpdatesKeyValuePair $updatesKeyValuePair
     */
    public function __construct(CreatesKeyValuePair $createsKeyValuePair, UpdatesKeyValuePair $updatesKeyValuePair)
    {
        $this->createsKeyValuePair = $createsKeyValuePair;
        $this->updatesKeyValuePair = $updatesKeyValuePair;
    }

    /**
     * @return array
     */
    protected function notification():array {
        return [
            'title' => 'Import Excel',
            'message' => 'You have successfully imported data from excel file'
        ];
    }


    /**
     * @param Request $request
     * @return JsonResponse
     * @throws MalformedRequestException
     */
    public function logic(Request $request) : JsonResponse
    {
        $result = [];

        $reportType = $request->input('report_type');

        $object = new DocumentObject('', $request->input('files'), '', ApprovalStatus::APPROVED, 'imports');

        $files = $object->getFiles();

        if (count($files) > 1) {
            throw new MalformedRequestException('Import function can only process one file at a time.');
        }

        foreach ($files as $file) {
            $filePath = json_decode($file)->file_info->original->file;
            $import = new AutoCountDataImport($reportType);
            Excel::import($import, $filePath);
        }

        /*
        foreach ($files as $file) {
            $collection = Excel::toCollection(null, json_decode($file)->file_info->original->file, null, null, true);

            $sheet = $collection->first();
            $header = $sheet->first()->toArray();

            $normalizedHeader = array_map(fn($h) => strtolower(trim($h)), $header);
            $salesInvoiceHeader = [
                'docno', 'docdate', 'debtorcode', 'ref', 'shipinfo', 'accno',
                'detaildescription', 'furtherdescription', 'classification',
                'deptno', 'qty', 'unitprice', 'submiteinvoice', 'consolidatedeinvoice'
            ];
            $customersReportHeader = [
                'tin', 'identityno', 'name', 'identitytype', 'taxclassification', 'msiccode',
                'businessactivitydesc', 'debtorcode', 'tradename', 'address', 'postcode',
                'phone', 'emailaddress', 'city', 'countrycode', 'statecode'
            ];
            $paymentReportHeader = [
                'docno',
                'docdate',
                'debtorcode',
                'description',
                'paymentmethod',
                'paymentamt',
                'knockoffdocno'
            ];

            $creditNoteReportHeader = [
                'docno',
                'docdate',
                'debtorcode',
                'ref',
                'description',
                'reason',
                'deptno',
                'qty',
                'unitprice',
                'accno',
                'submiteinvoice',
                'einvoiceissuedatetime',
                'consolidatedeinvoice',
                'einvoicevalidationlink'
            ];


            if ($reportType === 'Sales Invoice Report') {
                $optionalColumn = 'einvoicevalidationlink';

                if (
                    $normalizedHeader !== $salesInvoiceHeader &&
                    $normalizedHeader !== [...$salesInvoiceHeader, $optionalColumn]
                ) {
                    throw new MalformedRequestException('Uploaded Excel file format is incorrect. Column headers do not match expected format.');
                }

            }
            elseif ($reportType === 'Customers Report' && $normalizedHeader !== $customersReportHeader) {
                throw new MalformedRequestException('Uploaded Excel file format is incorrect. Column headers do not match expected format.');
            }
            elseif ($reportType === '01R - RECEIVE PAYMENT [AR RECEIVE PAYMENT]' && $normalizedHeader !== $paymentReportHeader) {
                throw new MalformedRequestException('Uploaded Excel file format is incorrect. Column headers do not match expected format.');
            }
            elseif ($reportType === 'Credit Note Report' && $normalizedHeader !== $creditNoteReportHeader) {
                throw new MalformedRequestException('Uploaded Excel file format is incorrect. Column headers do not match expected format.');
            }

            if ($reportType === 'Sales Invoice Report') {
                $this->processSalesInvoiceReport($sheet);
            }
            else if ($reportType === '01R - RECEIVE PAYMENT [AR RECEIVE PAYMENT]'){
                $result = $this->processPaymentReport($sheet);
                $result = [
                    'message' => empty($result)
                        ? ''
                        : 'Some data are unprocessed: ',
                    'data' => $result
                ];
            }
            else if ($reportType === 'Credit Note Report') {
                $result = $this->processCreditNoteReport($sheet);
                $result = [
                    'message' => empty($result)
                        ? ''
                        : 'Some data are unprocessed: ',
                    'data' => $result
                ];
            }
            else{
                throw new MalformedRequestException('Cannot process report type: ' . $reportType);
            }
        }
        */
        return $this->response($result);
    }

    private function updateOrCreateKeyValuePair($booking, $key, $value)
    {
        $keyValuePairObject = new KeyValuePairObject($key, $value);
        $metadata = $booking->attributesKVP()->where('key', $key)->first();

        if ($metadata) {
            $this->updatesKeyValuePair->execute($metadata, $keyValuePairObject);
        } else {
            $this->createsKeyValuePair->execute($booking, $keyValuePairObject);
        }
    }

    private function processSalesInvoiceReport($sheet){
        $rows = $sheet->skip(1);

        foreach ($rows as $index => $details) {
            $docNo = $details[0] ?? null;
            $docDate = $details[1] ?? null;
            $debtorCode = $details[2] ?? null;
            $ref = $details[3] ?? null;
            $shipInfo = $details[4] ?? null;
            $accNo = $details[5] ?? null;
            $detailDescription = $details[6] ?? null;
            $furtherDescription = $details[7] ?? null;
            $classification = $details[8] ?? null;
            $deptNo = $details[9] ?? null;
            $qty = $details[10] ?? null;
            $unitPrice = $details[11] ?? null;
            $submitEinvoice = $details[12] ?? null;
            $consolidatedEinvoice = $details[13] ?? null;
            $eInvoiceValidationLink = $details[14] ?? null; // Safe access for the new column

            Log::info("Row {$index} Details:", [
                'DocNo' => $docNo,
                'DocDate' => $docDate,
                'DebtorCode' => $debtorCode,
                'Ref' => $ref,
                'ShipInfo' => $shipInfo,
                'AccNo' => $accNo,
                'DetailDescription' => $detailDescription,
                'FurtherDescription' => $furtherDescription,
                'Classification' => $classification,
                'DeptNo' => $deptNo,
                'Qty' => $qty,
                'UnitPrice' => $unitPrice,
                'SubmitEinvoice' => $submitEinvoice,
                'ConsolidatedEinvoice' => $consolidatedEinvoice,
                'EInvoiceValidationLink' => $eInvoiceValidationLink,
            ]);

            // $booking = Booking::where('marking', $ref)->first();
            // if($booking){
            //     if($docNo != "" && $docNo != "<<New>>"){
            //         $this->updateOrCreateKeyValuePair($booking, KVPKey::AUTOCOUNT_DOCNO_INVOICE, $docNo);
            //     }
            //     if($eInvoiceValidationLink){
            //         $this->updateOrCreateKeyValuePair($booking, KVPKey::AUTOCOUNT_EINVOICE_VALIDATION_LINK, $eInvoiceValidationLink);
            //     }
            // }
            ProcessSalesInvoiceReportV2CommandJob::dispatch($details);
        }
    }

    private function processPaymentReport($sheet){
        $unprocessedKnockOffs = [];
        $rows = $sheet->skip(1);

        foreach ($rows as $index => $details) {
            $docNo = $details[0] ?? null;
            $docDate = $details[1] ?? null;
            $debtorCode = $details[2] ?? null;
            $description = $details[3] ?? null;
            $paymentMethod = $details[4] ?? null;
            $paymentAmt = $details[5] ?? null;
            $knockOffDocNo = $details[6] ?? null;

            Log::info("Row {$index} Payment Details:", [
                'DocNo' => $docNo,
                'DocDate' => $docDate,
                'DebtorCode' => $debtorCode,
                'Description' => $description,
                'PaymentMethod' => $paymentMethod,
                'PaymentAmt' => $paymentAmt,
                'KnockOffDocNo' => $knockOffDocNo,
            ]);

            if($knockOffDocNo)
            {
                ProcessPaymentReportV2CommandJob::dispatch($details);
                // $kvp = KeyValuePair::where('key', KVPKey::AUTOCOUNT_DOCNO_INVOICE)->where('value', $knockOffDocNo)->first();
                // if($kvp){
                //     $booking = $kvp->owner;
                //     if($booking){
                //         if($docNo != "" && $docNo != "<<New>>"){
                //             $this->updateOrCreateKeyValuePair($booking, KVPKey::AUTOCOUNT_DOCNO_OFFICIAL_RECEIPT, $docNo);
                //         }
                //         // if($eInvoiceValidationLink){
                //         //     $this->updateOrCreateKeyValuePair($booking, KVPKey::AUTOCOUNT_EINVOICE_VALIDATION_LINK, $eInvoiceValidationLink);
                //         // }
                //     }
                //     else{
                //         $unprocessedKnockOffs[] = $knockOffDocNo;
                //     }
                // }
                // else{
                //     $unprocessedKnockOffs[] = $knockOffDocNo;
                // }
            }
        }

        return $unprocessedKnockOffs;
    }

    private function processCreditNoteReport($sheet){
        $unprocessedDocNos = [];
        $rows = $sheet->skip(1);

        foreach ($rows as $index => $details) {
            $docNo = $details[0] ?? null;
            $docDate = $details[1] ?? null;
            $debtorCode = $details[2] ?? null;
            $ref = $details[3] ?? null;
            $description = $details[4] ?? null;
            $reason = $details[5] ?? null;
            $deptNo = $details[6] ?? null;
            $qty = $details[7] ?? null;
            $unitPrice = $details[8] ?? null;
            $accNo = $details[9] ?? null;
            $submitEinvoice = $details[10] ?? null;
            $einvoiceIssueDateTime = $details[11] ?? null;
            $consolidatedEinvoice = $details[12] ?? null;
            $eInvoiceValidationLink = $details[13] ?? null;

            Log::info("Row {$index} processCreditNoteReport:", [
                'DocNo' => $docNo,
                'DocDate' => $docDate,
                'DebtorCode' => $debtorCode,
                'Ref' => $ref,
                'Description' => $description,
                'Reason' => $reason,
                'DeptNo' => $deptNo,
                'Qty' => $qty,
                'UnitPrice' => $unitPrice,
                'AccNo' => $accNo,
                'SubmitEinvoice' => $submitEinvoice,
                'EInvoiceIssueDateTime' => $einvoiceIssueDateTime,
                'ConsolidatedEinvoice' => $consolidatedEinvoice,
                'EInvoiceValidationLink' => $eInvoiceValidationLink,
            ]);

            $booking = Booking::where('marking', $ref)->first();
            if($booking){
                if($docNo != "" && $docNo != "<<New>>"){
                    $payments = $booking->transactions()->payments()->get();
                    $processed = false;
                    foreach ($payments as $payment) {
                        $refundTransaction = $payment->transactions()->refunds()->whereIn('status', [ApprovalStatus::APPROVED, ApprovalStatus::COMPLETED])->latest()->first();
                        if($refundTransaction){
                            $this->updateOrCreateKeyValuePair($refundTransaction, KVPKey::AUTOCOUNT_DOCNO_CREDIT_NOTE, $docNo);
                            if($eInvoiceValidationLink){
                                $this->updateOrCreateKeyValuePair($refundTransaction, KVPKey::AUTOCOUNT_EINVOICE_VALIDATION_LINK_CREDIT_NOTE, $eInvoiceValidationLink);
                            }
                            $processed = true;
                            break;
                        }
                    }
                    if(!$processed){
                        $unprocessedDocNos[] = $docNo;
                    }
                }
            }
            else{
                $unprocessedDocNos[] = $docNo;
            }
        }

        return $unprocessedDocNos;
    }
}
