<?php

namespace App\Http\Controllers;

use App\Http\Requests\VoucherRequest;
use App\Models\Budget;
use App\Models\CreditLine;
use App\Models\Currency;
use App\Models\Debt;
use App\Models\Kardex;
use App\Models\profitDetails;
use App\Models\Quota;
use App\Models\StatementOfAccount;
use App\Models\Voucher;
use App\Models\VoucherDetail;
use App\Models\warehouse;
use App\Models\WarehouseDetail;
use Barryvdh\DomPDF\Facade\Pdf;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Mail;
use Inertia\Inertia;
use Luecano\NumeroALetras\NumeroALetras;
use Carbon\Carbon;

class VoucherController extends Controller
{
    /**
     * Display a listing of the resource.
     */
    public function index()
    {
        $query = Voucher::where('status', '1')
            ->with('person')
            ->with('warehouse')
            ->with('budget')
            ->with('voucher_type')
            ->where('voucher_type_id', request()->input('voucher_type_id'))
            ->where('type_transaction', request()->input('type_transaction'))
            ->latest('id');

        if (request()->input('person')) {
            $query->whereHas('person', function ($q) {
                $q->where("legal_name", "LIKE", "%" . request()->input('person') . "%");
            });
        }

        if (request()->input('warehouse')) {
            $query->whereHas('warehouse', function ($q) {
                $q->where("name", "LIKE", "%" . request()->input('warehouse') . "%");
            });
        }

        $vouchers = $query->paginate(10)->withQueryString();

        return Inertia::render('Vouchers/Index', [
            'vouchers' => $vouchers,
            'type_transaction' => request()->input('type_transaction'),
            'voucher_type_id' => request()->input('voucher_type_id')
        ]);
    }

    /**
     * Show the form for creating a new resource.
     */
    public function create()
    {
        $currencies = Currency::all();
        $warehouse = warehouse::with('establishment')->first();

        return Inertia::render('Vouchers/CreateEdit', [
            'currencies' => $currencies,
            'warehouse' => $warehouse,
            'series' => (new Voucher())->getSeries(request()->input('voucher_type_id')),
            'correlative' => (new Voucher())->getCorrelative(request()->input('voucher_type_id'), request()->input('type_transaction')),
            'type_transaction' => request()->input('type_transaction'),
            'voucher_type_id' => request()->input('voucher_type_id')
        ]);
    }

    /**
     * Store a newly created resource in storage.
     */
    public function store(VoucherRequest $request)
    {
        $request['number'] = $request->input('series') . '-' . $request->input('correlative');
        if (Voucher::where('number', $request['number'])->where('type_transaction', $request->input('type_transaction'))->where('status', '1')->first()) {
            $series = (new Voucher())->getSeries(request()->input('voucher_type_id'));
            $correlative = (new Voucher())->getCorrelative(request()->input('voucher_type_id'), request()->input('type_transaction'));

            return redirect()->back()->withErrors([
                'series' => $series,
                'correlative' => $correlative
            ]);
        }

        \DB::transaction(function () use ($request) {
            $voucher = new Voucher($request->input());
            $voucher->status = 1;
            $voucher->save();

            $this->createOrCancelVoucherDetail($request->input()['details'], $voucher, $request->input('type_transaction'));
            if ($request->input('paymentType') === 'credit') {
                $debt = new StatementOfAccount(['person_id' => $voucher->person_id, 'voucher_id' => $voucher->id, 'type_transaction' => $request->input('type_transaction'), 'total' => $voucher->total, 'issue_date' => $voucher->issue_date]);
                $debt->save();
                $typeTransaction = $request->input('type_transaction') === 'sales' ? 'output' : 'entry';

                if ($typeTransaction === 'output') {
                    $creditLine = CreditLine::where('person_id', $voucher->person_id)->first();
                    if ($creditLine) {
                        $creditLine->used += $voucher->total;
                        $creditLine->residue = $creditLine->total - $creditLine->used;
                        $creditLine->save();
                    }
                }
            }

            foreach ($request->input()['quotas'] as $quota) {
                $quota = new Quota(array_merge($quota, ['type_document' => 'voucher', 'document_id' => $voucher->id]));
                $quota->save();
            }

            if ($voucher->voucher_type_id === 1 && $voucher->paymentType === 'credit') {
                $debt = new Debt(['date' => $voucher->issue_date, 'voucher_id' => $voucher->id, 'status' => 'pending', 'total_amount' => $voucher->total, 'pending_amount' => $voucher->total]);
                $debt->save();
            }

            $budget = Budget::findOrFail($request->input('budget_id'));
            $budget->status_traffic_light = 3;
            $budget->save();
        });

        return redirect()->route($request->input('type_transaction') . '.' . ($request->input('voucher_type_id') === 1 ? 'invoices' : 'tickets') . '.index');
    }

    /**
     * Display the specified resource.
     */
    public function show(string $id)
    {
        $voucher = Voucher::where('status', '1')
            ->where('id', $id)
            ->with('person.doctype')
            ->with('person.district.province.department')
            ->with('budget')
            ->with('warehouse.establishment')
            ->with('details.product.unitOfMeasure')
            ->with('voucher_type')
            ->with('currency')
            ->with('quotas')
            ->with('people_role')
            ->first();
        $employee = $voucher->getPeopleRoleByName($voucher->people_role->id);
        $voucher->peopleRol = $employee;

        return $voucher;
    }

    /**
     * Show the form for editing the specified resource.
     */
    public function edit(Voucher $voucher)
    {
        $currencies = Currency::all();


        $voucher->load('person.doctype');
        $voucher->load('budget');
        $voucher->load('warehouse.establishment');
        $voucher->load('details.product.unitOfMeasure');
        $voucher->load('quotas');
        $voucher->load('people_role');

        $employee = $voucher->getPeopleRoleByName($voucher->people_role_id);
        $voucher->peopleRol = $employee;

        $budgetName = $voucher->budget_id ? $voucher->budget->name : null;

        return Inertia::render('Vouchers/CreateEdit', ['currencies' => $currencies, 'document' => $voucher, 'voucher_type_id' => $voucher->voucher_type_id, 'type_transaction' => $voucher->type_transaction]);
    }

    /**
     * Update the specified resource in storage.
     */
    public function update(VoucherRequest $request, Voucher $voucher)
    {
        \DB::transaction(function () use ($request, $voucher) {
            $this->createOrCancelVoucherDetail($voucher->details(), $voucher, $request->input('type_transaction'), true);

            $voucher->update($request->input());
            $voucher->details()->update(['status' => '0']);
            $voucher->details()->delete();
            $voucher->quotas()->delete();

            $voucher->profit_details()->update(['status' => '0']);
            $voucher->profit_details()->delete();

            $this->createOrCancelVoucherDetail($request->input()['details'], $voucher, $request->input('type_transaction'));

            foreach ($request->input()['quotas'] as $quota) {
                $quota = new Quota(array_merge($quota, ['type_document' => 'voucher', 'document_id' => $voucher->id]));
                $quota->save();
            }

            $budget = Budget::findOrFail($request->input('budget_id'));
            $budget->status_traffic_light = 3;
            $budget->save();
        });

        return redirect()->route($request->input('type_transaction') . '.' . ($request->input('voucher_type_id') === 1 ? 'invoices' : 'tickets') . '.index');
    }

    public function createOrCancelVoucherDetail($details, $voucher, $type_transaction, $isCancellation = false)
    {
        foreach ($details as $detail) {
            if (!$isCancellation) {
                $detail = new VoucherDetail(array_merge($detail, ['voucher_id' => $voucher->id]));
                $detail->status = 1;
                $detail->save();

                $totalCost = $detail->cost * $detail->quantity;
                $subtotal = $detail->priceWithoutTax * $detail->quantity;
                $profit_subtotal = $subtotal - $totalCost;
                if ($totalCost != 0) {
                    $percentage_subtotal = round(($profit_subtotal / $totalCost) * 100, 2);
                } else {
                    $percentage_subtotal = 0 ;
                }
                $total = $detail->priceWithTax * $detail->quantity;

                $profit_total = $total - $totalCost;
                if ($totalCost != 0) {
                    $percentage_total = round(($profit_total / $totalCost) * 100, 2);
                } else {
                    $percentage_total = 0;
                }

                $profitDetail = new profitDetails(array_merge(
                    $detail->toArray(),
                    [
                        'currency_id' => $voucher->currency_id,
                        'total_cost' => $totalCost,
                        'profit_subtotal' => $profit_subtotal,
                        'profit_total' => $profit_total,
                        'percentage_subtotal' => $percentage_subtotal,
                        'percentage_total' => $percentage_total,
                    ]
                ));

                $profitDetail->save();
            }

            $warehouse_detail = WarehouseDetail::where('product_id', $detail->product_id)->where('warehouse_id', $voucher->warehouse_id)->first();

            if ($warehouse_detail) {
                $type = $type_transaction === 'sales' ? 'output' : 'entry';
                if ($isCancellation) {
                    $type = $type . ' cancellation';
                }

                $kardex = new Kardex(['warehouse_detail_id' => $warehouse_detail->id,
                    'voucher_id' => $voucher->id,
                    'type' => $type,
                    'cost' => $detail->product->cost,
                    'price' => $detail->priceWithTax,
                    'quantity' => $detail->quantity]);
                $kardex->save();

                if ($type == 'entry') {
                    if ($isCancellation) {
                        $warehouse_detail->stock -= $detail->quantity;
                    } else {
                        $warehouse_detail->stock += $detail->quantity;
                    }

                } else {
                    if ($isCancellation) {
                        $warehouse_detail->stock += $detail->quantity;
                    } else {
                        $warehouse_detail->stock -= $detail->quantity;
                    }

                }
                $warehouse_detail->save();
            }
        }
    }

    /**
     * Remove the specified resource from storage.
     */
    public function destroy(Voucher $voucher)
    {
        $voucher->load('statementOfAccounts.transaction_details.transaction.transaction_details.StatementOfAccount');
        $this->createOrCancelVoucherDetail($voucher->details(), $voucher, $voucher->type_transaction, true);
        $voucher->status = 0;
        $voucher->save();
        $voucher->delete();
        $typeTransaction = $voucher->type_transaction === 'sales' ? 'output' : 'entry';

        if ($typeTransaction === 'output') {
            $creditLine = CreditLine::where('person_id', $voucher->person_id)->first();
            if ($creditLine) {
                $creditLine->used += $voucher->total;
                $creditLine->residue = $creditLine->total - $creditLine->used;
                $creditLine->save();
            }
        }

        foreach ($voucher->statementOfAccounts as $statementOfAccount) {
            if ($statementOfAccount->transaction_details->count() > 0) {
                foreach ($statementOfAccount->transaction_details as $transactionDetail) {
                    $transactionDetailsArray = $transactionDetail->transaction->transaction_details;
                    if ($transactionDetailsArray->count() > 0) {
                        foreach ($transactionDetailsArray as $detail) {
                            $detail->StatementOfAccount->payment_status = 0;
                            $detail->StatementOfAccount->save();

                            $detail->status = 0;
                            $detail->save();
                            $detail->delete();

                        }
                    }

                    $transactionDetail->transaction->status = 0;
                    $transactionDetail->transaction->save();
                    $transactionDetail->transaction->delete();

                    $transactionDetail->status = 0;
                    $transactionDetail->save();
                    $transactionDetail->delete();
                }
            }
            $statementOfAccount->status = 0;
            $statementOfAccount->save();
            $statementOfAccount->delete();

        }
        return redirect()->route($voucher->type_transaction . '.invoices.index');
    }

    public function downloadPDF(Request $request)
    {
        $pdf = $this->createPDF($request->input('id'));
        $voucher = $this->show($request->input('id'));

        if ($pdf) {
            return $pdf->download($voucher->voucher_type->name . ' ' . $voucher->number . '.pdf');
        }

        return response()->json(['error' => 'Hubo un error al generar el PDF.'], 400);
    }

    public function createPDF($voucherID)
    {
        $voucher = $this->show($voucherID);

        if ($voucher) {
            $pdf = Pdf::loadView('pdf.vouchers.voucher', ['voucher' => $voucher, 'textAmount' => (new NumeroALetras())->toMoney($voucher->total, 2, $voucher->currency->description, 'CENTAVOS')]);
            return $pdf;
        }

        return null;
    }

    public function sendPDFtoEmail(Request $request)
    {
        $voucher = $this->show($request->input('id'));
        $pdf = $this->createPDF($request->input('id'));

        if (!$pdf) {
            return response()->json(['error' => 'Hubo un error al generar el PDF.'], 400);
        }

        if (!$voucher) {
            return response()->json(['error' => 'No se pudo obtener los datos del comprobante'], 400);
        }

        if (!$voucher->person->email) {
            return response()->json(['error' => 'El ' . $voucher->type_transaction === 'sales' ? 'cliente' : 'proveedor' . ' no cuenta con correo electrónico.'], 400);
        }

        $data["emailTo"] = $voucher->person->email;
        $data["person"] = $voucher->person->legal_name;
        $data["identifierDocument"] = $voucher->number;

        try {
            Mail::send('emails.vouchers.pdf', $data, function ($message) use ($pdf, $data, $voucher) {
                $message->to($data["emailTo"], $data['person'])->subject($voucher->voucher_type->name . ' ' . $data['identifierDocument']);
                $message->attachData($pdf->output(), $voucher->voucher_type->name . ' ' . $data['identifierDocument'] . '.pdf');
            });

            return response()->json(['response' => 'PDF enviado correctamente.'], 200);
        } catch (\Throwable $th) {
            return response()->json(['error' => 'Hubo un error al enviar el PDF.'], 400);
        }
    }

    public function getbudgetsByName()
    {
        $query = Budget::with('vouchers')
            ->where('status', 1)
            ->where('name', 'LIKE', '%' . request()->input('name') . '%');

        if (!request()->input('name')) {
            $query->take(10);
        }

        $budgets = $query->get();

        foreach ($budgets as $budget) {
            $employee = $budget->getPeopleRoleByName($budget->people_role_id);
            $budget->peopleRol = $employee;
        }

        return $budgets;
    }

    public function getVouchersLastMonth()
    {

        $currentMonthStart = Carbon::now()->startOfMonth()->format('Y-m-d H:i:s');
        $currentMonthEnd = Carbon::now()->endOfMonth()->format('Y-m-d H:i:s');
        $previousMonthStart = Carbon::now()->subMonth()->startOfMonth()->format('Y-m-d H:i:s');
        $previousMonthEnd = Carbon::now()->subMonth()->endOfMonth()->format('Y-m-d H:i:s');

        $currentMonthSales = $this->getSalesData($currentMonthStart, $currentMonthEnd);
        $previousMonthSales = $this->getSalesData($previousMonthStart, $previousMonthEnd);
        $currentMonthPurchases = $this->getPurchasesData($currentMonthStart, $currentMonthEnd);
        $previousMonthPurchases = $this->getPurchasesData($previousMonthStart, $previousMonthEnd);

        return response()->json([
            'currentMonthSales' => $currentMonthSales,
            'currentMonthPurchases' => $currentMonthPurchases,
            'previousMonthSales' => $previousMonthSales,
            'previousMonthPurchases' => $previousMonthPurchases
        ], 200);
    }

    private function getSalesData($startDate, $endDate)
    {
        return Voucher::where('status', '1')
            ->with('person')
            ->with('warehouse')
            ->with('budget')
            ->with('voucher_type')
            ->where('type_transaction', 'sales')
            ->where('vouchers.created_at', '>=', $startDate)
            ->where('vouchers.created_at', '<=', $endDate)
            ->latest('id')
            ->get();
    }

    private function getPurchasesData($startDate, $endDate)
    {
        return Voucher::where('status', '1')
            ->with('person')
            ->with('warehouse')
            ->with('budget')
            ->with('voucher_type')
            ->where('type_transaction', 'purchases')
            ->where('vouchers.created_at', '>=', $startDate)
            ->where('vouchers.created_at', '<=', $endDate)
            ->latest('id')
            ->get();
    }
}
