<?php

namespace App\Http\Controllers\Reports;

use App\Http\Controllers\Controller;
use App\Models\Items\ItemTransaction;
use App\Models\Purchase\Purchase;
use App\Models\Purchase\PurchaseReturn;
use App\Models\Sale\Sale;
use App\Models\Sale\SaleReturn;
use App\Traits\FormatNumber;
use App\Traits\FormatsDateInputs;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Validator;

class GstReportController extends Controller
{
    use FormatNumber;
    use FormatsDateInputs;

    public function getGstr1Records(Request $request): JsonResponse
    {
        try {
            // Validation rules
            $rules = [
                'from_date' => ['required', 'date_format:'.implode(',', $this->getDateFormats())],
                'to_date' => ['required', 'date_format:'.implode(',', $this->getDateFormats())],
            ];

            $validator = Validator::make($request->all(), $rules);

            if ($validator->fails()) {
                throw new \Exception($validator->errors()->first());
            }

            $fromDate = $request->input('from_date');
            $fromDate = $this->toSystemDateFormat($fromDate);
            $toDate = $request->input('to_date');
            $toDate = $this->toSystemDateFormat($toDate);

            $preparedData = ItemTransaction::with(['transaction'])
                ->whereHasMorph('transaction', [Sale::class, SaleReturn::class], function ($query) use ($fromDate, $toDate) {
                    $query->whereBetween('transaction_date', [$fromDate, $toDate]);
                })
                ->selectRaw('transaction_id, transaction_type, tax_id, sum(tax_amount) as tax_amount, (sum(total) - sum(tax_amount)) as taxable_value')
                ->groupBy('tax_id', 'transaction_id', 'transaction_type')
                ->get();

            if ($preparedData->count() == 0) {
                throw new \Exception('No Records Found!!');
            }

            $recordsArray = [];

            foreach ($preparedData as $data) {
                $transactionDate = $data->transaction instanceof Sale ? $data->transaction->sale_date : $data->transaction->return_date;
                $transactionType = $data->transaction instanceof Sale ? 'Sale' : 'Sale Return';
                $invoiceNumber = $data->transaction instanceof Sale ? $data->transaction->sale_code : $data->transaction->return_code;
                $stateName = $data->transaction->state ? $data->transaction->state->name : '';

                $companyStateID = app('company')['state_id'];
                $invoiceStateID = $data->transaction->party->state_id;

                // GST Calculation
                $taxAmount = $data->tax_amount;
                $cs_gst_amt = $i_gst_amt = 0;
                if (empty($invoiceStateID) || $companyStateID == $invoiceStateID) {
                    $cs_gst_amt = $this->formatWithPrecision($taxAmount / 2, comma: false);
                } else {
                    $i_gst_amt = $this->formatWithPrecision($taxAmount, comma: false);
                }
                // end

                $recordsArray[] = [
                    'tax_number' => $data->transaction->party->tax_number ?? '',
                    'party_name' => $data->transaction->party->getFullName(),
                    'transaction_type' => $transactionType,
                    'transaction_date' => $this->toUserDateFormat($transactionDate),
                    'invoice_or_bill_code' => $invoiceNumber,
                    'invoice_value' => $data->transaction->grand_total,
                    'tax_rate' => $data->tax->rate,
                    'taxable_value' => $data->taxable_value,
                    'cgst_value' => $cs_gst_amt,
                    'sgst_value' => $cs_gst_amt,
                    'igst_value' => $i_gst_amt,
                    'state_of_supply' => $stateName,
                ];
            }

            return response()->json([
                'status' => true,
                'message' => 'Records are retrieved!!',
                'data' => $recordsArray,
            ]);
        } catch (\Exception $e) {
            return response()->json([
                'status' => false,
                'message' => $e->getMessage(),
            ], 409);

        }
    }

    public function getGstr2Records(Request $request): JsonResponse
    {
        try {
            // Validation rules
            $rules = [
                'from_date' => ['required', 'date_format:'.implode(',', $this->getDateFormats())],
                'to_date' => ['required', 'date_format:'.implode(',', $this->getDateFormats())],
            ];

            $validator = Validator::make($request->all(), $rules);

            if ($validator->fails()) {
                throw new \Exception($validator->errors()->first());
            }

            $fromDate = $request->input('from_date');
            $fromDate = $this->toSystemDateFormat($fromDate);
            $toDate = $request->input('to_date');
            $toDate = $this->toSystemDateFormat($toDate);

            $preparedData = ItemTransaction::with(['transaction'])
                ->whereHasMorph('transaction', [Purchase::class, PurchaseReturn::class], function ($query) use ($fromDate, $toDate) {
                    $query->whereBetween('transaction_date', [$fromDate, $toDate]);
                })
                ->selectRaw('transaction_id, transaction_type, tax_id, sum(tax_amount) as tax_amount, (sum(total) - sum(tax_amount)) as taxable_value')
                ->groupBy('tax_id', 'transaction_id', 'transaction_type')
                ->get();

            if ($preparedData->count() == 0) {
                throw new \Exception('No Records Found!!');
            }

            $recordsArray = [];

            foreach ($preparedData as $data) {
                $transactionDate = $data->transaction instanceof Purchase ? $data->transaction->purchase_date : $data->transaction->return_date;
                $transactionType = $data->transaction instanceof Purchase ? 'Purchase' : 'Purchase Return';
                $invoiceNumber = $data->transaction instanceof Purchase ? $data->transaction->purchase_code : $data->transaction->return_code;
                $stateName = $data->transaction->state ? $data->transaction->state->name : '';

                $companyStateID = app('company')['state_id'];
                $invoiceStateID = $data->transaction->party->state_id;

                // GST Calculation
                $taxAmount = $data->tax_amount;
                $cs_gst_amt = $i_gst_amt = 0;
                if (empty($invoiceStateID) || $companyStateID == $invoiceStateID) {
                    $cs_gst_amt = $this->formatWithPrecision($taxAmount / 2, comma: false);
                } else {
                    $i_gst_amt = $this->formatWithPrecision($taxAmount, comma: false);
                }
                // end

                $recordsArray[] = [
                    'tax_number' => $data->transaction->party->tax_number ?? '',
                    'party_name' => $data->transaction->party->getFullName(),
                    'transaction_type' => $transactionType,
                    'transaction_date' => $this->toUserDateFormat($transactionDate),
                    'invoice_or_bill_code' => $invoiceNumber,
                    'invoice_value' => $data->transaction->grand_total,
                    'tax_rate' => $data->tax->rate,
                    'taxable_value' => $data->taxable_value,
                    'cgst_value' => $cs_gst_amt,
                    'sgst_value' => $cs_gst_amt,
                    'igst_value' => $i_gst_amt,
                    'state_of_supply' => $stateName,
                ];
            }

            return response()->json([
                'status' => true,
                'message' => 'Records are retrieved!!',
                'data' => $recordsArray,
            ]);
        } catch (\Exception $e) {
            return response()->json([
                'status' => false,
                'message' => $e->getMessage(),
            ], 409);

        }
    }
}
