<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Models\User;
use Carbon\Carbon;
use OneSignal;
use App\Models\Suppliers;
use App\Models\Categories;
use App\Models\Postulations;
use App\Models\Property;
use App\Models\iChambaParameter;
use MissaelAnda\Whatsapp;
use MissaelAnda\Whatsapp\Messages;
use App\Models\FinishedContracts;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Facades\Validator;
use TarfinLabs\LaravelSpatial\Types\Point;

class PostulationController extends Controller
{
    //
    public function index(Request $request)
    {
        //
        $request->session()->put('search', $request
              ->has('search') ? strip_tags($request->get('search')) : ($request->session()
              ->has('search') ? strip_tags($request->session()->get('search')) : ''));

        $request->session()->put('field', $request
                ->has('field') ? strip_tags($request->get('field')) : ($request->session()
                ->has('field') ? strip_tags($request->session()->get('field')) : 'id'));

        $request->session()->put('sort', $request
                ->has('sort') ? strip_tags($request->get('sort')) : ($request->session()
                ->has('sort') ? strip_tags($request->session()->get('sort')) : 'asc'));

        //$headers = $request->get('header') != '' ? $request->get('header') : -1;

        $postulations = new Postulations();
        $postulations = $postulations->where('id', 'LIKE', '%' . strip_tags($request->session()->get('search')) . '%')
                              ->orwhere('user_id', 'LIKE', '%' . strip_tags($request->session()->get('search')) . '%')
                              ->orwhere('address', 'LIKE', '%' . strip_tags($request->session()->get('search')) . '%')
                              ->orwhere('amount', 'LIKE', '%' . strip_tags($request->session()->get('search')) . '%')
                        ->orderBy(strip_tags($request->session()->get('field')), strip_tags($request->session()->get('sort')))
                        ->paginate(10);

        if ($request->ajax()) {
            return view('postulations.index', compact('postulations'));
          } else {
            return view('postulations.ajax', compact('postulations'));
          }

    }

    public function map(Request $request)
    {
        //
        $request->session()->put('search', $request
              ->has('search') ? strip_tags($request->get('search')) : ($request->session()
              ->has('search') ? strip_tags($request->session()->get('search')) : ''));

        $request->session()->put('field', $request
                ->has('field') ? strip_tags($request->get('field')) : ($request->session()
                ->has('field') ? strip_tags($request->session()->get('field')) : 'id'));

        $request->session()->put('sort', $request
                ->has('sort') ? strip_tags($request->get('sort')) : ($request->session()
                ->has('sort') ? strip_tags($request->session()->get('sort')) : 'asc'));

        //$headers = $request->get('header') != '' ? $request->get('header') : -1;

        $postulations = new Postulations();
        $postulations = $postulations->where('id', 'LIKE', '%' . strip_tags($request->session()->get('search')) . '%')
                              ->orwhere('user_id', 'LIKE', '%' . strip_tags($request->session()->get('search')) . '%')
                              ->orwhere('address', 'LIKE', '%' . strip_tags($request->session()->get('search')) . '%')
                              ->orwhere('amount', 'LIKE', '%' . strip_tags($request->session()->get('search')) . '%')
                        ->orderBy(strip_tags($request->session()->get('field')), strip_tags($request->session()->get('sort')))
                        ->paginate(10);

      return view('postulations.map', compact('postulations'));

    }

    /**
     * Show the form for creating a new resource.
     *
     * @return \Illuminate\Http\Response
     */
    public function create(Request $request) {

      $rules = [
        'category'               => 'required|string',
        'property_id'            => 'required|numeric',
        'references'             => 'string|nullable',
        'details'                => 'string|nullable',
        'photos'                 => 'nullable|array',
        'photos.*'               => 'nullable|image|max:4096',
        'related_postulation_id' => 'nullable|numeric|exists:postulations,id',
      ];

      $validator = Validator::make($request->all(), $rules);
      if ($validator->fails()) {
        return response()->json($validator->messages());
      } else {

        $user     = Auth::user();
        $property = Property::find($request->property_id);

        if (!$property || $property->user_id !== $user->id) {
            return response()->json(['message' => 'Propiedad no válida'], 403);
        }

        $geometry = new Point($property->lat, $property->lng);
        $category = Categories::where('name', strip_tags($request->category))->orwhere('en_name', strip_tags($request->category))->first();

        $distance = 5000; // metros (5 km)
        $suppliers = Suppliers::withinDistanceTo('location', $geometry, $distance)->get();

        if ($suppliers != '[]') {

          $postulation = new Postulations();
          $postulation->user_id     = $user->id;
          $postulation->category_id = $category->id;
          $postulation->property_id = $property->id;
          $postulation->address     = $property->address;
          $postulation->location    = $geometry;
          $postulation->int_number  = $property->int_number;
          $postulation->references             = preg_replace('/\d+/', '', strip_tags($request->references));
          $postulation->amount                 = null;
          $postulation->details                = preg_replace('/\d+/', '', strip_tags($request->details));
          $postulation->status                 = 'active';
          $postulation->related_postulation_id = $request->related_postulation_id;
          $postulation->save();

          // Subir fotos a storage
          if ($request->hasFile('photos')) {
              $disk      = Storage::disk(env('STORAGE_DISK', 'gcs'));
              $photoUrls = [];
              foreach ($request->file('photos') as $i => $photo) {
                  $filename    = time() . '_' . $i . '.' . $photo->getClientOriginalExtension();
                  $disk->putFileAs('img/postulations/' . $postulation->id . '/', $photo, $filename, 'public');
                  $photoUrls[] = $disk->url('img/postulations/' . $postulation->id . '/' . $filename);
              }
              $postulation->photos = $photoUrls;
              $postulation->save();
          }

          try {
            OneSignal::sendNotificationToExternalUser(
               "Coméntele al Ing. que hay una postulación",
               "128",
               null, null, null, null,
               "Admin: hay nueva postulación"
            );
          } catch (\Exception $e) {}

          foreach ($suppliers as $supplier) {
            if (in_array($category->id, $supplier->categories->pluck('id')->toArray())) {
              try {
                OneSignal::sendNotificationToExternalUser(
                   "Dirígete a la sección de postulaciones en la app para ver más detalles",
                   (string) $supplier->user_id,
                   null, null, null, null,
                   "Proveedor: hay nueva postulación"
                );
              } catch (\Exception $e) {}

              // TODO: Configurar WhatsApp cuando esté disponible
              // Whatsapp::send($supplier->user->phone, Messages\TemplateMessage::create()
              // ->name('suppplier_new_postulation')
              // ->language('es_US')
              // ->body(Messages\Components\Body::create([
              //     Messages\Components\Parameters\Text::create('Proveedor hay nueva postulación: dirígete a la sección de postulaciones en JobHero para ver más detalles'),
              // ])));

            }
          }

          $delay_UTC = Carbon::now()->addMinutes(15)->toString();

          try {
            OneSignal::sendNotificationToExternalUser(
               "Dirígete a la sección de contratos en la app para ver más detalles",
               (string) $user->id,
               null, null, null,
               $delay_UTC,
               "Búsqueda Finalizada"
            );
          } catch (\Exception $e) {}

          return response()->json([
              'message' => 'Servicio solicitado, espere a que un proveedor se postule'
          ]);
        } else {
          return response()->json([
              'message' => 'No Provider'
          ]);
        }
      }
    }

    public function postulate(Request $request) {

      $rules = [
        'postulation_id' => 'required|numeric',
        'date_1'         => 'required|date',
        'date_2'         => 'required|date',
        'amount'         => 'required|numeric|min:0',
      ];

      $validator = Validator::make($request->all(), $rules);
      if ($validator->fails()) {
        return response()->json($validator->errors(), 422);
      }

      $user         = Auth::user();
      $postulation  = Postulations::where('id', $request->postulation_id)->first();
      $time_created = Carbon::parse($postulation->created_at);
      $time_limit   = (1000 - Carbon::now()->diffInMinutes($time_created));
      $supplier     = Suppliers::where('user_id', $user->id)->first();

      if (!$supplier) {
        return response()->json([
          'success' => false,
          'message' => 'No tienes un perfil de proveedor registrado'
        ], 400);
      }

      // Validar cuota mínima del sistema
      $minFeeParam = iChambaParameter::where('parameter', 'ichamba_fee')->first();
      if ($minFeeParam && $request->amount < $minFeeParam->num_value) {
        return response()->json([
          'message' => 'El monto es menor a la cuota mínima del sistema (' . $minFeeParam->num_value . ')'
        ], 422);
      }

      if ($time_limit > 0) {
        if (in_array($postulation->category_id, $supplier->categories->pluck('id')->toArray())) {
          if ($supplier->membership == 1) {
            try {
              OneSignal::sendNotificationToExternalUser(
                 "Dirígete a la sección de contratos en la app para ver más detalles",
                 (string) $postulation->user_id,
                 null, null, null, null,
                 "Un proveedor certificado se ha postulado"
              );
            } catch (\Exception $e) {}
          }

          $supplier->postulations()->attach($request->postulation_id, [
              'date_1' => Carbon::parse($request->date_1),
              'date_2' => Carbon::parse($request->date_2),
              'amount' => $request->amount,
          ]);

          return response()->json([
              'message' => 'Se ha postulado al servicio exitosamente'
          ]);
        }
      } else {
        return response()->json([
            'message' => 'La postulación ha caducado'
        ]);
      }
    }

    public function getpendingcontracts(Request $request) {
      $user = Auth::user();
      $postulations = Postulations::where('user_id', $user->id)
                          ->where('status', 'active')
                          ->orderBy('created_at', 'DESC')
                          ->get();
      $pendingcontracts  = array();

        foreach($postulations as $postulation) {
            $category = Categories::where('id', $postulation->category_id)->first();
            $pendingcontractinfo = array(
              'id'          => $postulation->id,
              'category'    => $category->name,
              'en_category' => $category->en_name,
              'address'     => $postulation->address,
              'date'        => $postulation->appointment,
              'amount'      => $postulation->amount,
              'property_id'  => $postulation->property_id,
              'references'   => $postulation->references,
              'details'      => $postulation->details,
              'time_created' => $postulation->created_at,
            );
            $pendingcontracts[] = $pendingcontractinfo;
        }

        return response()->json($pendingcontracts);
    }

    public function getfinishedpostulations(Request $request) {
      $user = Auth::user();

      if (!$user->suppliers) {
        return response()->json([
          'success' => false,
          'message' => 'No tienes un perfil de proveedor registrado'
        ], 400);
      }

      $supplier = $user->suppliers;
      $postulations = FinishedContracts::with(['technician.user'])
          ->where('supplier_id', $supplier->id)->orderBy('created_at', 'DESC')->get();
      $finishedpostulations  = array();

        foreach($postulations as $postulation) {
            $category = Categories::where('id', $postulation->category_id)->first();
            $technician = $postulation->technical_id
                ? ($postulation->technician->user->name ?? null)
                : ($supplier->user->name ?? null);
            $finishedpostulationinfo = array(
              'id' => $postulation->id,
              'category' => $category->name,
              'en_category' => $category->en_name,
              'address' => $postulation->address,
              'date' => $postulation->appointment,
              'amount' => $postulation->amount,
              'technician' => $technician
            );
            $finishedpostulations[] = $finishedpostulationinfo;
        }

        return response()->json($finishedpostulations);
    }

    public function getpostulants(Request $request) {

      $rules = [
        'postulation_id' => 'required|numeric',
      ];

      $validator = Validator::make($request->all(), $rules);
      if ($validator->fails()) {
        return response()->json($validator->errors(), 422);
      }

      $user        = Auth::user();
      $postulation = Postulations::with('suppliers')->where('id', $request->postulation_id)->first();

      if ($postulation->user_id == $user->id) {
        $category  = Categories::where('id', $postulation->category_id)->first();
        $suppliers = $postulation->suppliers;

        $pcontractsuppliers = array();

        if ($suppliers->isNotEmpty()) {
          foreach ($suppliers as $supplier) {
            $pivot = $supplier->pivot;
            $pcontractsupplier = array(
              'id'          => $postulation->id,
              'category'    => $category->name,
              'en_category' => $category->en_name,
              'address'     => $postulation->address,
              'supplier_id' => $supplier->id,
              'supplier'    => $supplier->company_name,
              'tags'        => $supplier->tags,
              'cover_photo' => $supplier->cover_photo,
              'membership'  => $supplier->membership,
              'fee'         => $pivot->amount,
              'date_1'      => $pivot->date_1,
              'date_2'      => $pivot->date_2,
              'score'       => $supplier->finished_jobs > 0
                                   ? round($supplier->total_score / $supplier->finished_jobs, 1)
                                   : null,
            );
            $pcontractsuppliers[] = $pcontractsupplier;
          }

          $collection = collect($pcontractsuppliers);
          $sort       = $request->get('sort', 'membership');

          if ($sort === 'date') {
              $pcontractsupplier = $collection->sortBy('date_1')->values()->all();
          } elseif ($sort === 'amount') {
              $pcontractsupplier = $collection->sortBy('fee')->values()->all();
          } else {
              $pcontractsupplier = $collection->sortByDesc('membership')->sortByDesc('score')->values()->all();
          }

        } else {
            $pcontractsupplier = array(
              'id'          => $postulation->id,
              'category'    => $category->name,
              'en_category' => $category->en_name,
              'address'     => $postulation->address,
              'supplier_id' => null,
              'supplier'    => null,
              'tags'        => null,
              'cover_photo' => null,
              'membership'  => null,
              'fee'         => null,
              'date_1'      => null,
              'date_2'      => null,
              'score'       => null,
            );

          $pcontractsuppliers[] = $pcontractsupplier;
          $pcontractsupplier = $pcontractsuppliers;
          }
          return response()->json($pcontractsupplier);
        }
    }

    public function deleteexpired()
    {
      $postulations = Postulations::whereDate('appointment', '<', Carbon::now())->delete();
    }

    public function cancelPostulation($id)
    {
        $user        = Auth::user();
        $postulation = Postulations::find($id);

        if (!$postulation || $postulation->user_id !== $user->id) {
            return response()->json(['message' => 'No autorizado'], 403);
        }

        $postulation->status = 'perdido';
        $postulation->save();
        return response()->json(['message' => 'Postulación archivada']);
    }

    public function updatePostulation(Request $request, $id)
    {
        $user        = Auth::user();
        $postulation = Postulations::find($id);

        if (!$postulation || $postulation->user_id !== $user->id) {
            return response()->json(['message' => 'No autorizado'], 403);
        }

        $rules = [
            'references' => 'nullable|string',
            'details'    => 'nullable|string',
            'photos'     => 'nullable|array',
            'photos.*'   => 'nullable|image|max:4096',
        ];

        $validator = Validator::make($request->all(), $rules);
        if ($validator->fails()) {
            return response()->json($validator->errors(), 422);
        }

        if ($request->has('references')) {
            $postulation->references = preg_replace('/\d+/', '', strip_tags($request->references));
        }
        if ($request->has('details')) {
            $postulation->details = preg_replace('/\d+/', '', strip_tags($request->details));
        }

        if ($request->hasFile('photos')) {
            $disk      = Storage::disk(env('STORAGE_DISK', 'gcs'));
            $photoUrls = [];
            foreach ($request->file('photos') as $i => $photo) {
                $filename    = time() . '_' . $i . '.' . $photo->getClientOriginalExtension();
                $disk->putFileAs('img/postulations/' . $postulation->id . '/', $photo, $filename, 'public');
                $photoUrls[] = $disk->url('img/postulations/' . $postulation->id . '/' . $filename);
            }
            $postulation->photos = $photoUrls;
        }

        $postulation->save();
        return response()->json(['message' => 'Postulación actualizada']);
    }

    public function destroy($id)
    {
      Postulations::destroy($id);
      return redirect('postulations');
    }

}
