<?php

namespace App\Http\Controllers;

use App\Constants;
use App\Http\Requests\BudgetRequest;
use App\Models\Budget;
use App\Models\BudgetDetail;
use App\Models\CreditLine;
use App\Models\Currency;
use App\Models\Person;
use App\Models\Quota;
use App\Models\Voucher;
use App\Models\warehouse;
use App\Models\peopleRole;
use Barryvdh\DomPDF\Facade\Pdf;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Response;
use Illuminate\Support\Facades\Storage;
use Inertia\Inertia;
use Luecano\NumeroALetras\NumeroALetras;
use Mail;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Style\Alignment;
use PhpOffice\PhpSpreadsheet\Style\Fill;
use PhpOffice\PhpSpreadsheet\Writer\Xlsx;
class BudgetController extends Controller
{
    /**
     * Display a listing of the resource.
     */
    public function index()
    {
        $query = Budget::where('status', '1')
            ->with('person')
            ->with('warehouse')
            ->with('voucher_type')
            ->where('type_transaction', request()->input('type_transaction'))
            ->latest('id');

        if (request()->input('name')) {
            $query->where('name', 'LIKE', '%' . request()->input('name') . '%');
        }

        if (request()->input('number')) {
            $query->where('number', 'LIKE', '%' . request()->input('number') . '%');
        }

        if (request()->input('issue_date')) {
            $query->where('issue_date', 'LIKE', '%' . request()->input('issue_date') . '%');
        }

        if (request()->input('paymentType')) {
            $query->where('paymentType', 'LIKE', '%' . request()->input('paymentType') . '%');
        }

        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') . "%");
            });
        }

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

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

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

    /**
     * Show the form for creating a new resource.
     */
    public function create()
    {
        $currencies = Currency::all();
        $warehouse = warehouse::with('establishment')->first();
        $series = (new Budget())->getSeries();
        $correlative = (new Budget())->getCorrelative(request()->input('type_transaction'));

        return Inertia::render('Budgets/CreateEdit', [
            'currencies' => $currencies,
            'name' => 'Cotizacion ' . $series . '-' . $correlative . ' ' . date('d-m-Y'),
            'warehouse' => $warehouse,
            'series' => $series,
            'correlative' => $correlative,
            'budget_type' => 1,
            'type_transaction' => request()->input('type_transaction')
        ]);
    }

    /**
     * Store a newly created resource in storage.
     */
    public function store(BudgetRequest $request)
    {
        $request['number'] = $request->input('series') . '-' . $request->input('correlative');

        if (Budget::where('number', $request['number'])->where('type_transaction',$request->input('type_transaction'))->where('status', '1')->first()) {
            $series = (new Budget())->getSeries();
            $correlative = (new Budget())->getCorrelative($request->input('type_transaction'));

            return redirect()->back()->withErrors([
                'series' => $series,
                'correlative' => $correlative,
                'name_budget' => 'Cotizacion ' . $series . '-' . $correlative . ' ' . date('d-m-Y'),
            ]);
        }

        $typeTransaction = $request->input('type_transaction') === 'sales' ? 'output' : 'entry';
        if ($typeTransaction === 'output' && $request->input('paymentType') != 'counted') {
            $creditLine = CreditLine::where('person_id', $request['person_id'])->first();
            if ($creditLine) {
                if ($creditLine->residue < $request['total']) {
                    return redirect()->back()->withErrors([
                        'credit_line_error' => 'La línea de crédito Restante: ' . $creditLine->residue.' es insuficiente para cubrir el total de la Cotizacion: '. $request['total'],
                    ]);
                }
            }}
        \DB::transaction(function () use ($request) {
            $budget = new Budget($request->input());
            $budget->status = 1;
            $budget->save();

            foreach ($request->input()['details'] as $detail) {
                $detail = new BudgetDetail(array_merge($detail, ['budget_id' => $budget->id]));
                $detail->status = 1;
                $detail->save();
            }

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

        return redirect()->route($request->input('type_transaction') . '.budgets.index');
    }

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

        $budget->load('people_role');

        $employee = $budget->getPeopleRoleByName($budget->people_role->id);
        $budget->peopleRol = $employee;
        return $budget;
    }

    /**
     * Showq the form for editing the specified resource.
     */
    public function edit(Budget $budget)
    {
        $currencies = Currency::all();
        $budget->load([
            'person.doctype',
            'warehouse.establishment',
            'details.product.unitOfMeasure',
            'details.product.prices.details',
            'quotas',
            'people_role'
        ]);

        $employee = $budget->getPeopleRoleByName($budget->people_role->id);
        $budget->peopleRol = $employee;

        $data = ['currencies' => $currencies, 'document' => $budget, 'budget_type' => 1, 'type_transaction' => $budget->type_transaction];
        return Inertia::render('Budgets/CreateEdit', $data);
    }

    /**
     * Update the specified resource in storage.
     */
    public function update(BudgetRequest $request, Budget $budget)
    {
        \DB::transaction(function () use ($request, $budget) {
            $budget->update($request->input());
            $budget->details()->update(['status' => '0']);
            $budget->details()->delete();

            $budget->quotas()->delete();

            foreach ($request->input()['details'] as $detail) {
                $detail = new BudgetDetail(array_merge($detail, ['budget_id' => $budget->id]));
                $detail->status = 1;
                $detail->save();
            }

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

        return redirect()->route($request->input('type_transaction') . '.budgets.index');
    }

    /**
     * Remove the specified resource from storage.
     */
    public function destroy(Budget $budget)
    {
        $budget->status = 0;
        $budget->save();
        $budget->delete();
        return redirect()->route($budget->type_transaction . '.budgets.index');
    }



    /**
     * Update the specified resource in storage.
     */
    public function approve(Request $request, $id)
    {
        $request->validate([
            'status_traffic_light' => 'required|integer|in:1,2,3',
        ]);

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

        return redirect()->route($budget->type_transaction . '.budgets.index');
    }




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

        if ($pdf) {
            return $pdf->download('Cotizacion ' . $budget->number . '.pdf');
        }

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

    public function downloadNewPDF(string $id)
    {
        $jsonTemplate = Storage::get('public/json/factura.json');
        $json = json_decode($jsonTemplate, true);
        $budget = $this->show($id);
        $delimiterPos = strrpos($budget->number, '-');
        $serie = substr($budget->number, 0, $delimiterPos);
        $numero = substr($budget->number, $delimiterPos + 1);

        $json['serie'] = $serie;
        $json['correlativo'] = $numero;
        $json['fechaEmision'] =date("Y-m-d\TH:i:sP", strtotime($budget->issue_date));
        $waytoPay = 'Credito';
        if ($budget->paymentType == 'counted') {
            $waytoPay = 'Contado';
        }

        $json['formaPago']['tipo'] = $waytoPay;
        $typeDoc = '1';
        if ($budget->person->doctype->description == 'RUC') {
            $typeDoc = '6';
        }

        $json['client']['tipoDoc'] = $typeDoc;
        $json['client']['numDoc'] = $budget->person->document_number;
        $json['client']['rznSocial'] = $budget->person->legal_name;
        $json['client']['address']['direccion'] = $budget->person->direction;
        $json['moneda'] = $budget->currency->description;
        $json['sellerName'] = $budget->peopleRol->legal_name;
        $json['sellerPhone'] = $budget->peopleRol->personPhones->pluck('phone')->implode(', ');
        $json['sellerEmail'] = $budget->peopleRol->email;

        $json['mtoOperGravadas'] = number_format((float)($budget->subtotal + $budget->discounts), 2, '.', '');
        $json['mtoIGV'] = number_format((float)$budget->igv, 2, '.', '');
        $json['totalImpuestos'] = number_format((float)$budget->igv, 2, '.', '');
        $json['valorVenta'] = number_format((float)($budget->subtotal + $budget->discounts), 2, '.', '');
        $json['subTotal'] = number_format((float)$budget->total, 2, '.', '');
        $json['mtoImpVenta'] = number_format((float)$budget->total, 2, '.', '');
        $json['observacion'] = $budget->observations;
        $json['legends'][0]['value'] = (new NumeroALetras())->toMoney($budget->total, 2, $budget->currency->description, 'CENTAVOS');

        $arr_detalle_sunat = array();
        foreach ($budget->details as $key => $d) {
            $igv = (number_format((float)$d->total, 2, '.', '')) - number_format((float)$d->priceWithoutTax, 2, '.', '');

            $precioUnitario = number_format((float)$d->priceWithoutTax, 2, '.', '');
            $precioUnitarioIgv = number_format((float)$d->priceWithTax, 2, '.', '');
            $prod = (object)[
                'unidad' => $d->product->unitOfMeasure->description,
                'cantidad' => (float)$d->quantity,
                'codProducto' => $d->product->code,
                'descripcion' => $d->product->name,
                'mtoValorUnitario' => number_format((float)$d->priceWithoutTax, 2, '.', ''),
                'mtoBaseIgv' => number_format((float)$d->subtotal, 2, '.', ''),
                'porcentajeIgv' => 18.0,
                'igv' => $igv,
                "tipAfeIgv" => 10,
                'totalImpuestos' => $igv,
                'mtoPrecioUnitario' => number_format((float)$precioUnitario, 2, '.', ''),
                'mtoValorVenta' => (number_format((float)$d->total, 2, '.', '')),
            ];
            $arr_detalle_sunat[$key] = $prod;
        }

        $json['details'] = $arr_detalle_sunat;
        $response = Http::post(Constants::urlFacturador . 'invoice/pdf?token=123456', $json);

        if ($response->successful()) {
            $pdfContent = $response->getBody();

            return response($pdfContent, 200)
                ->header('Content-Type', 'application/pdf')
                ->header('Content-Disposition', 'inline; filename=" ' . $budget->number . '.pdf"');

        } else {

            return response()->json(['error' => 'No se pudo generar el PDF'], $response->status());
        }

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

    public function createPDF($budgetID)
    {
        $budget = $this->show($budgetID);
        if ($budget) {
            $view = view('pdf.budgets.budget', [
                'budget' => $budget,
                'textAmount' => (new NumeroALetras())->toMoney($budget->total, 2, $budget->currency->description, 'CENTAVOS')
            ])->render();
            $encodings = ['UTF-8', 'ISO-8859-1', 'Windows-1252'];
            $currentEncoding = mb_detect_encoding($view, $encodings, true);
            if ($currentEncoding === false) {
                $currentEncoding = 'UTF-8';
            }
            $html = mb_convert_encoding($view, 'UTF-8', $currentEncoding);

            return Pdf::loadHTML($html);
        }

        return null;
    }

    public function downloadNewEXCEL(Request $request)
    {

        $ids = $request->query('ids', '');
        $idsArray = explode(',', $ids);
        $idsArray = array_map('intval', $idsArray);
       $budgets = Budget::whereIn('status_traffic_light', $idsArray)->get();

        $budgetIds = $budgets->pluck('id');
        $budgetDetails = BudgetDetail::join('products', 'budget_detail.product_id', '=', 'products.id')
            ->whereIn('budget_detail.budget_id', $budgetIds)
            ->select('budget_detail.product_id', 'products.name as product_name')
            ->selectRaw('SUM(budget_detail.quantity) as total_quantity')
            ->groupBy('budget_detail.product_id', 'products.name')
            ->get();

        $spreadsheet = new Spreadsheet();
        $sheet = $spreadsheet->getActiveSheet();

        $headerCellStyle = [
            'fill' => [
                'fillType' => Fill::FILL_SOLID,
                'color' => ['argb' => 'FFBF5700']
            ],
            'font' => [
                'bold' => true,
                'color' => ['argb' => 'FFFFFFFF'],
            ],
            'alignment' => [
                'horizontal' => Alignment::HORIZONTAL_CENTER,
            ],
        ];

        $sheet->setCellValue('B3', 'Item');
        $sheet->setCellValue('C3', 'Producto');
        $sheet->setCellValue('D3', 'Cantidad');
        $sheet->getStyle('B3:D3')->applyFromArray($headerCellStyle);
        $sheet->getColumnDimension('B')->setWidth(5);
        $sheet->getColumnDimension('C')->setWidth(60);
        $sheet->getColumnDimension('D')->setWidth(20);

        $itemCellStyle = [
            'alignment' => [
                'horizontal' => Alignment::HORIZONTAL_CENTER,
            ],
        ];

        $productCellStyle = [
            'alignment' => [
                'horizontal' => Alignment::HORIZONTAL_LEFT,
            ],
        ];

        $quantityCellStyle = [
            'alignment' => [
                'horizontal' => Alignment::HORIZONTAL_RIGHT,
            ],
        ];

        $row = 4;
        foreach ($budgetDetails as $index => $detail) {
            $sheet->setCellValue('B' . $row, $index + 1);
            $sheet->setCellValue('C' . $row, $detail->product_name);
            $sheet->setCellValue('D' . $row, $detail->total_quantity);
            $row++;
        }

        $sheet->getStyle('B4:B' . ($row - 1))->applyFromArray($itemCellStyle);
        $sheet->getStyle('C4:C' . ($row - 1))->applyFromArray($productCellStyle);
        $sheet->getStyle('D4:D' . ($row - 1))->applyFromArray($quantityCellStyle);

        $writer = new Xlsx($spreadsheet);
        $filename = 'Presupuestos.xlsx';
        return Response::stream(
            function () use ($writer) {
                $writer->save('php://output');
            },
            200,
            [
                'Content-Type' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
                'Content-Disposition' => "attachment; filename=\"{$filename}\"",
            ]
        );

    }

    public function sendPDFtoEmail(Request $request)
    {
        $budget = $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 (!$budget) {
            return response()->json(['error' => 'No se pudo obtener los datos de la cotización'], 400);
        }

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

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

        try {
            Mail::send('emails.budgets.pdf', $data, function ($message) use ($pdf, $data) {
                $message->to($data["emailTo"], $data['person'])->subject('Cotización ' . $data['identifierDocument']);
                $message->attachData($pdf->output(), 'Cotización ' . $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 createVoucher(string $id)
    {
        $budget = $this->show($id);
        $budget->load('people_role');

        $employee = $budget->getPeopleRoleByName($budget->people_role->id);
        $budget->peopleRol = $employee;
        if ($budget) {
            $currencies = Currency::all();
            return Inertia::render('Vouchers/CreateEdit', [
                'currencies' => $currencies,
                'document' => $budget,
                'budget' => $budget,
                'voucher_type_id' => $budget->voucher_type_id,
                'type_transaction' => $budget->type_transaction,
                'series' => (new Voucher())->getSeries($budget->voucher_type_id),
                'correlative' => (new Voucher())->getCorrelative($budget->voucher_type_id,$budget->type_transaction ),
                'isFromBudget' => true,
                'budget_id' => $id
            ]);
        }

        return Inertia::render('NotFound');
    }

    public function getpeopleRoleByName($people_role_id)
    {
        $clients =Person::join('people_role', 'people.id', '=', 'people_role.people_id')
            ->with('doctype')
            ->where('people_role.role_id', 2)
            ->where('people.status', 1)
            ->where('people_role.id', $people_role_id)
            ->where('legal_name', 'LIKE', '%' . request()->input('name') . '%')
            ->select('people.*', 'people_role.id as people_role_id')
            ->latest('people.id')
            ->get();

        return $clients;
    }
}
