<?php

use App\Http\Controllers\LaporanController;
use App\Services\Reports\RingkasanHarianService;
use Illuminate\Http\Request;

class RingkasanHarianServicesTest extends TestCase
{
    private $kodCawangan = 'kb2';
    private $startDate = '2023-03-23';
    private $endDate = '2023-03-23';
    /**
     * A basic test example.
     *
     * @return void
     */
    public function test_have_errors()
    {
        $request = new Request;
        $request->startDate = $this->startDate;
        $request->endDate = $this->endDate;
        $ringkasanHarianService = new RingkasanHarianService($this->kodCawangan, $request);

        $this->expectNotToPerformAssertions();
        return $ringkasanHarianService->generate();

    }

    public function test_service_method_output_is_same_originated_method()
    {

        $request = new Request;
        $request->startDate = $this->startDate;
        $request->endDate = $this->endDate;
        $ringkasanHarianService = new RingkasanHarianService($this->kodCawangan, $request);
        $outputService = $ringkasanHarianService->generate();

        $request = new Request;
        $request->tarikh = $this->startDate;
        $request->kodcaw = $this->kodCawangan;
        $outputOriginatedMethod = (new LaporanController)->laporanHarian($request);

        // Find divergent properties and values
        $divergentProperties = [];

        $outputOriginatedMethod = $outputOriginatedMethod->getData()[0];
        $outputService = $outputService->getData()[0];

        $this->show_diverged_changes($outputOriginatedMethod, $outputService);

        $this->assertEquals($outputOriginatedMethod, $outputService);

    }

    public function test_date_range_of_test_service_method_ouput_is_same_as_originated_method()
    {

        // Properties are excluded because all property values from originated report are assummed to sum between 2 days.
        // But these properties are already utilize range. So summing these property values will result in false output
        $propertiesToBeExcludedFromTest = [
           'panjar_bulanan',
           'panjar_tahunan',
           'stokauditpembiayaan',
           'stokauditnilaimarhun',
           'stokauditcount',
           'petibesiimbangduga',
           'outstandingimbangduga',
           'rekodpemb',
           'rekodpembnm',
           'rekodpembbil',
           'bayaranpend',
        ];

        $prepareReport = function($report) use($propertiesToBeExcludedFromTest){
            foreach ($propertiesToBeExcludedFromTest as $properties) {
              unset($report->$properties);
            }

            return $report;
        };

        $day1 = '2023-03-20';
        $day2 = '2023-03-21';
        $kodCawangan = $this->kodCawangan;

        $report1 = $this->get_2_days_report_from_originated_method($kodCawangan, $day1, $day2);

        $request = new Request;
        $request->startDate = $day1;
        $request->endDate = $day2;
        $ringkasanHarianService = new RingkasanHarianService($kodCawangan, $request);
        $outputService = $ringkasanHarianService->generate();
        $report2 = $this->convert_object_values_to_string($outputService->getData()[0]);

        $this->assertEquals($prepareReport($report1), $prepareReport($report2));

    }

    public function show_diverged_changes($outputOriginatedMethod, $outputService)
    {

        // Get properties dynamically from the first object
        $properties = array_keys(get_object_vars($outputOriginatedMethod));

        // Find divergent properties and values
        $divergentProperties = [];

        foreach ($properties as $property) {
            $value1 = $outputOriginatedMethod->$property;
            $value2 = $outputService->$property;

            if ($value1 !== $value2) {
                $divergentProperties[$property] = [
                    'value1' => $value1,
                    'value2' => $value2,
                ];
            }
        }

        // Display divergent properties and values
        if (!empty($divergentProperties)) {
            dump("Divergent properties found:\n");
            foreach ($divergentProperties as $property => $values) {

                $value1 = in_array(gettype($values['value1']), ['integer', 'string']) ? $values['value1'] : json_encode($values['value1']);
                $value2 = in_array(gettype($values['value2']), ['integer', 'string']) ? $values['value2'] : json_encode($values['value2']);

                dump("$property: outputOriginatedMethod : {$value1} vs serviceMethod : {$value2}\n");
            }
        }
    }

    private function get_2_days_report_from_originated_method($kodCawangan, $day1, $day2)
    {

        $requestFirstDay = new Request;
        $requestFirstDay->tarikh = $day1;
        $requestFirstDay->kodcaw = $kodCawangan;

        $requestSecondDay = new Request;
        $requestSecondDay->tarikh = $day2;
        $requestSecondDay->kodcaw = $kodCawangan;

        $outputFirstDay = (new LaporanController)->laporanHarian($requestFirstDay)->getData()[0];
        $outputSecondDay = (new LaporanController)->laporanHarian($requestSecondDay)->getData()[0];

        $sumDateRangeReportData = function ($report1, $report2) {
            $floatingPointProperty = [
                'total_gadai',
                'gadai_70',
                'gadai_75',
                'gadai_80',
                'nilaimarhun_70',
                'nilaimarhun_75',
                'nilaimarhun_80',
                'panjar_harian',
                'panjar_bulanan',
                'panjar_tahunan',
                'stokauditpembiayaan',
                'stokauditnilaimarhun',
                'stokauditcount',
                'petibesiimbangduga',
                'outstandingimbangduga',
                'rekodpemb',
                'rekodpembnm',
                'rekodpembil',
                'bayaranpend',
            ];
            // Merge objects by summing corresponding values
            $mergedReport = new stdClass();

            foreach ($report1 as $key => $value) {
                // Check if the property exists in the second object
                if (property_exists($report2, $key)) {
                    // Sum the values and assign to the merged object
                    $sum = $value + $report2->$key;
                    $mergedReport->$key = in_array($key, $floatingPointProperty) ? floatval($sum) : $sum;
                }
            }

            return $mergedReport;
        };

        $sum = $sumDateRangeReportData($outputFirstDay, $outputSecondDay);

        return $this->convert_object_values_to_string($sum);
    }

    private function convert_object_values_to_string($inputObject) {
        // Check if the input is an object
        if (!is_object($inputObject)) {
            // Handle the case where the input is not an object
            return $inputObject;
        }

        // Create a new stdClass object to store the converted values
        $convertedObject = new stdClass();

        // Iterate through the properties of the input object
        foreach ($inputObject as $key => $value) {
            // Convert the value to string and assign it to the new object
            $convertedObject->$key = number_format($value, 2);
        }

        return $convertedObject;
    }

}
