<?php

namespace App\Http\Controllers\Front;

use App\Enums\TipoPromocion;
use App\Http\Controllers\Controller;
use App\Http\Requests\PromocionesRequest;
use App\Http\Resources\DefaultCollection;
use App\Http\Resources\DefaultResource;
use App\Models\Bank;
use App\Models\Files;
use App\Models\Promociones;
use App\Models\Servicio;
use App\Services\UploadedImageService;
use Carbon\Carbon;
use GuzzleHttp\Psr7\Response;
use Illuminate\Http\Request;
use Illuminate\Http\Response as HttpResponse;
use Illuminate\Support\Facades\DB;

class PromocionesController extends Controller
{
    public function index(): DefaultCollection
    {
        $size = request('page.size', 10);
        $page = request('page', 1);

        $sort = request('sort', null);

        $dias = request('dias', []);
        $bankIds = $this->resolveBankIds(
            request('bank_ids', []),
            request('bank_slugs', [])
        );

        $result = Promociones::from('promociones as p');
        if (sizeof($dias)) {
            $result = $result->leftJoin('promociones_dias as pd', 'pd.promocion_id', 'p.id')
                ->where(function ($query) use ($dias) {
                    $query->whereIn('pd.dia', $dias)
                        ->orWhere('all_dias', true);
                });
        }
        if (sizeof($bankIds)) {
            $result->whereIn('p.bank_id', $bankIds);
        }
        $result = $result->where('p.fecha_desde', '<=', Carbon::now())
            ->where('p.fecha_hasta', '>=', Carbon::now()->subDay())
            ->select(
                'p.id',
                'p.titulo',
                'p.slug',
                'p.subtitulo',
                'p.fecha_desde',
                'p.fecha_hasta',
                'p.estado',
                'p.orden',
                'p.all_dias',
                'p.all_estaciones',
                'p.operadores',
                'p.copete',
                'p.descripcion',
                'p.popup',
                'p.app',
                'p.id as image_large_getter'
            )
            ->where('operadores', false)
            ->activo()
            ->ordenar()
            ->applySorts($sort, 'id')
            ->groupBy('p.id')
            //->filterLike(request('filter', []))
            ->fastPaginate($size, ['id'], $page, $page);

        return DefaultCollection::make($result);
    }

    public function facets()
    {
        $dias = request('dias', []);
        $bankIds = $this->resolveBankIds(
            request('bank_ids', []),
            request('bank_slugs', [])
        );

        $availableBankSlugs = DB::table('banks as b')
            ->join('promociones as p', 'p.bank_id', '=', 'b.id')
            ->leftJoin('promociones_dias as pd', 'pd.promocion_id', '=', 'p.id')
            ->where('p.fecha_desde', '<=', Carbon::now())
            ->where('p.fecha_hasta', '>=', Carbon::now()->subDay())
            ->where('p.operadores', false)
            ->where('p.estado', true)
            ->when(sizeof($dias), function ($query) use ($dias) {
                $query->where(function ($innerQuery) use ($dias) {
                    $innerQuery->whereIn('pd.dia', $dias)
                        ->orWhere('p.all_dias', true);
                });
            })
            ->distinct()
            ->orderByRaw('ISNULL(b.order_no)')
            ->orderBy('b.order_no')
            ->orderBy('b.name')
            ->pluck('b.slug')
            ->values();

        $dayRows = DB::table('promociones as p')
            ->leftJoin('promociones_dias as pd', 'pd.promocion_id', '=', 'p.id')
            ->where('p.fecha_desde', '<=', Carbon::now())
            ->where('p.fecha_hasta', '>=', Carbon::now()->subDay())
            ->where('p.operadores', false)
            ->where('p.estado', true)
            ->when(sizeof($bankIds), function ($query) use ($bankIds) {
                $query->whereIn('p.bank_id', $bankIds);
            })
            ->get([
                'p.all_dias',
                'pd.dia',
            ]);

        $availableDayIds = collect($dayRows)
            ->flatMap(function ($row) {
                return $row->all_dias ? [1, 2, 3, 4, 5, 6, 7] : [$row->dia];
            })
            ->filter()
            ->unique()
            ->sort()
            ->values();

        return response()->json([
            'available_day_ids' => $availableDayIds,
            'available_bank_slugs' => $availableBankSlugs,
        ]);
    }

    public function banks()
    {
        return Bank::query()
            ->select([
                'id',
                'name',
                'slug',
                'order_no',
            ])
            ->whereHas('promotions', function ($query) {
                $query->where('fecha_desde', '<=', Carbon::now())
                    ->where('fecha_hasta', '>=', Carbon::now()->subDay())
                    ->where('operadores', false)
                    ->where('estado', true);
            })
            ->orderByRaw('ISNULL(order_no)')
            ->orderBy('order_no')
            ->orderBy('name')
            ->get();
    }

    public function days()
    {
        $dayRows = DB::table('promociones as p')
            ->leftJoin('promociones_dias as pd', 'pd.promocion_id', '=', 'p.id')
            ->where('p.fecha_desde', '<=', Carbon::now())
            ->where('p.fecha_hasta', '>=', Carbon::now()->subDay())
            ->where('p.operadores', false)
            ->where('p.estado', true)
            ->get([
                'p.all_dias',
                'pd.dia',
            ]);

        return collect($dayRows)
            ->flatMap(function ($row) {
                return $row->all_dias ? [1, 2, 3, 4, 5, 6, 7] : [$row->dia];
            })
            ->filter()
            ->unique()
            ->sort()
            ->values();
    }

    public function view($id, $slug)
    {
        $result = Promociones::query()
            ->select(
                'id',
                'titulo',
                'descripcion',
                'id as image_large_getter'
            )
            ->where('operadores', false)
            ->activo()
            ->where('id', $id)
            ->first();

        if (!$result) return abort(404);

        $titulo = $result->titulo;
        $descripcion = strip_tags(html_entity_decode($result->descripcion));
        $imagen = $result->image_large;

        return view('index', compact('titulo', 'descripcion', 'imagen'));
    }

    public function show($slug_id)
    {
        $id = preg_replace("/[^0-9]/", "", $slug_id);
        $result = Promociones::query()
            ->select(
                'id',
                'titulo',
                'slug',
                'subtitulo',
                'fecha_desde',
                'fecha_hasta',
                'all_dias',
                'all_estaciones',
                'operadores',
                'app',
                'copete',
                'descripcion',
                'id as image_large_getter'
            )
            ->where('operadores', false)
            ->activo()
            ->with('metodosPagos')
            ->where('id', $id)
            ->first();

        if (!$result) {
            abort(HttpResponse::HTTP_NOT_FOUND);
        }

        $result->estaciones = $result->estaciones()->where('estado', true)->get();

        $result->terminos_file_id = $this->fileAsset($result->file('terminos'));
        $result->estaciones_file_id = $this->fileAsset($result->file('estaciones'));

        return response()->json(
            $result->toArray(),
            HttpResponse::HTTP_OK,
            [],
            JSON_INVALID_UTF8_SUBSTITUTE | JSON_UNESCAPED_UNICODE
        );
    }

    public function popup()
    {
        return Promociones::query()
            ->select(
                'id',
                'titulo',
                'slug',
                'subtitulo',
                'fecha_desde',
                'fecha_hasta',
                'all_dias',
                'all_estaciones',
                'operadores',
                'app',
                'copete',
                'descripcion',
                'id as image_large_getter'
            )
            ->activo()
            ->with('metodosPagos', 'estaciones')
            ->where('popup', true)
            ->whereIn('app', TipoPromocion::valuesForGeneralAudience())
            ->where('fecha_desde', '<=', Carbon::now())
            ->where('fecha_hasta', '>=', Carbon::now())
            ->where('operadores', false)
            ->first();
    }

    public function destacados()
    {
        $tipoPromocion = $this->resolveAudienceValues();

        return Promociones::query()
            ->activo()
            ->where('fecha_desde', '<=', Carbon::now())
            ->where('fecha_hasta', '>=', Carbon::now())
            ->whereIn('app', $tipoPromocion)
            ->where('operadores', false)
            ->select(
                'id',
                'titulo',
                'slug',
                'subtitulo',

                'fecha_desde',
                'fecha_hasta',

                'estado',
                'orden',
                'all_dias',
                'all_estaciones',
                'operadores',
                'copete',
                'descripcion',
                'popup',
                'app',
                'id as image_large_getter'
            )
            ->with('servicios')
            ->ordenar()
            ->limit(4)
            ->get();
    }

    private function resolveAudienceValues(): array
    {
        $raw = request('app', null);

        if ($raw instanceof TipoPromocion) {
            return $raw->isVisibleInApp()
                ? TipoPromocion::valuesForAppAudience()
                : TipoPromocion::valuesForGeneralAudience();
        }

        if (is_bool($raw)) {
            return $raw
                ? TipoPromocion::valuesForAppAudience()
                : TipoPromocion::valuesForGeneralAudience();
        }

        if (is_numeric($raw)) {
            return ((int) $raw) === 1
                ? TipoPromocion::valuesForAppAudience()
                : TipoPromocion::valuesForGeneralAudience();
        }

        $normalized = is_string($raw) ? strtolower(trim($raw)) : null;

        return match ($normalized) {
            TipoPromocion::APP->value => TipoPromocion::valuesForAppAudience(),
            TipoPromocion::AMBAS->value => [TipoPromocion::AMBAS->value],
            '1', 'true' => TipoPromocion::valuesForAppAudience(),
            default => TipoPromocion::valuesForGeneralAudience(),
        };
    }

    public function fileAsset($id)
    {
        if ($id)
            return asset("/files/{$id}");
    }


















    public function store(PromocionesRequest $request, UploadedImageService $uploadedImageService): DefaultResource
    {
        $input = $this->formatRequest($request);

        //? IMAGEN
        $imagen = $request->file('imagen', null);
        unset($input['imagen']);

        //? POPUP
        $imagen_popup = $request->file('imagen_popup', null);
        unset($input['imagen_popup']);
        //Si no tenemos imagen popup
        // if (!$imagen_popup) {
        //     unset($input['popup']);
        // }

        $result = Promociones::create($input);
        $result->metodosPagos()->attach($input['metodos_pagos']);
        $result->servicios()->attach($input['servicios']);
        $result->estaciones()->attach($input['estaciones']);
        $result->dias()->attach($input['dias']);


        if ($request->hasFile('imagen')) {
            $result->imagen =
                $uploadedImageService
                ->setFile($imagen)
                ->setRelatedModel($result)
                ->move()
                ->createThumbnails()
                ->storeRelationship()
                ->getUrl('large');
        }

        return DefaultResource::make($result);
    }

    public function update(PromocionesRequest $request, $id, UploadedImageService $uploadedImageService): DefaultResource
    {
        $input = $this->formatRequest($request);

        //? IMAGEN
        $imagen = $request->file('imagen', null);
        unset($input['imagen']);

        //? POPUP
        $imagen_popup = $request->file('imagen_popup', null);
        unset($input['imagen_popup']);
        //Si no tenemos imagen popup
        /*if (!$imagen_popup) {
            unset($input['popup']);
        }*/

        $result = Promociones::find($id);
        $result->fill($input)->save();

        $result->metodosPagos()->sync($input['metodos_pagos']);
        $result->servicios()->sync($input['servicios']);
        $result->estaciones()->sync($input['estaciones']);
        $result->dias()->sync($input['dias']);

        if ($request->hasFile('imagen')) {
            $result->imagen =
                $uploadedImageService
                ->setFile($imagen)
                ->setRelatedModel($result)
                ->move()
                ->createThumbnails()
                ->storeRelationship()
                ->getUrl('large');
        }

        return DefaultResource::make($result);
    }

    private function formatRequest($request)
    {
        $input = $request->all();
        $isAllEstaciones = $request->get('all_estaciones', false);
        $isAllDias = $request->get('all_dias', false);

        //Eliminamos las estaciones
        if ($isAllEstaciones) {
            $input['estaciones'] = [];
        }

        //Eliminamos los dias
        if ($isAllDias) {
            $input['dias'] = [];
        }

        return $input;
    }

    public function edit($id): DefaultResource
    {
        $result = Promociones::query()
            ->find($id);

        //! Por si se requiera cambiar de 1:M a M:M
        $servicios = $result->servicios()->pluck('servicio_id');
        $result->servicio_id = sizeof($servicios) ? $servicios[0] : null;
        //$result->servicios = $result->servicios()->pluck('servicio_id');

        $result->metodos_pagos = $result->metodosPagos()->pluck('metodo_pago_id');
        $result->imagen = $result->imagen();

        if ($result->all_dias) {
            $result->dias = [
                1, 2, 3, 4, 5, 6, 7
            ];
        } else {
            $result->dias = $result->dias()->pluck('dia');
        }

        if ($result->all_estaciones) {
            $result->estaciones = DB::table('estaciones')->pluck('id');
        } else {
            $result->estaciones = $result->estaciones()->pluck('estacion_id');
        }

        return DefaultResource::make($result);
    }

    public function destroy($id): HttpResponse
    {
        Promociones::destroy($id);

        return response()->noContent();
    }

    public function uploadFile()
    {
        $file = request()->file('file');

        $model = new Files;
        $model->uploadBorrador($file, Promociones::class);
    }

    private function resolveBankIds(array $bankIds, array $bankSlugs): array
    {
        if (sizeof($bankIds)) {
            return $bankIds;
        }

        if (!sizeof($bankSlugs)) {
            return [];
        }

        return Bank::query()
            ->whereIn('slug', $bankSlugs)
            ->pluck('id')
            ->all();
    }
}
