<?php

namespace App\Repositories\Member\Address;

use App\Models\Address;
use App\Models\City;
use App\Models\District;
use App\Models\Province;
use App\Models\Subdistrict;
use App\Models\PosCode;

use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Http;
use Illuminate\Database\Eloquent\ModelNotFoundException;
use Illuminate\Support\Facades\Cache;

class MemberAddressRepository
{
    public function getList($request)
    {
        $model = Address::where('user_id', auth()->user()->id)->orderBy('created_at','desc')->paginate($request->limit);

        return $model;
    }

    public function geocode($params){

        $lat = @$params["latitude"];
        $lon = @$params["longitude"];
        $res = Cache::remember("geocode_$lat\_$lon", 60 * 60 * 24, function () use ($lat, $lon){
            return Http::get("https://nominatim.openstreetmap.org/reverse",[
                "email" => "husnusetiawan@gmail.com",
                "lat" => $lat,
                "lon" => $lon,
                "format" => "json"
            ])->json();
        });

  

        try {
            $address = @$res["address"];

            $posCode = PosCode::where("code", $address['postcode'])->firstOrFail();
 
            $province_id = $posCode->province_id ?? null;
            $city_id = $posCode->city_id ?? null;
            $district_id = $posCode->district_id ?? null;
            $subdistrict_id = $posCode->subdistrict_id ?? null;
            if ($address != null) {
                $addr_province = $address["state"] ?? $address["city"] ?? $posCode->province;
                $addr_city = $address["city"] ?? $address["county"] ?? $address["city_district"] ?? $posCode->city;
                $addr_district = $address["suburb"] ?? $address["district"] ?? $posCode->district;
                $addr_subdistrict = $address["neighbourhood"] ?? $address["village"] ?? $posCode->subdistrict;

                if ($addr_province != null && $province_id == null) {
                    // search by nominatim
                    $province = Province::whereRaw('name ILIKE ?', ['%' . trim($addr_province) . '%'])->first();

                    // search by poscode
                    if ($province == null) {
                        $province = Province::whereRaw('name ILIKE ?', ['%' . trim($posCode->province) . '%'])->first();
                    }

                    $province_id = $posCode->province_id ?? $province->id ?? null;
                
                }

                if ($addr_city != null && $city_id == null) {
                    // search by nominatim
                    $city = City::whereRaw('name ILIKE ?', ['%' . trim($addr_city) . '%'])
                    ->where("province_id", $province_id)
                    ->first();

                    // search by poscode
                    if ($city == null) {
                        $city = City::whereRaw('name ILIKE ?', ['%' . trim($posCode->city) . '%'])
                        ->where("province_id", $province_id)
                        ->first();
                    }

                    $city_id = $posCode->city_id ?? $city->id ?? null;
                }


                if ($addr_district != null && $district_id == null) {
                    // search by nominatim
                    $district = District::whereRaw('name ILIKE ?', ['%' . trim($addr_district) . '%'])
                    ->where("city_id", $city_id)
                    ->first();

                

                    // search by poscode
                    if ($district == null) {
                        $district = District::whereRaw('name ILIKE ?', ['%' . trim($posCode->district) . '%'])
                        ->where("city_id", $city_id)
                        ->first();
                    }

                

                    $district_id = $posCode->district_id ?? $district->id ?? null;
                }

                if ($addr_subdistrict != null && $subdistrict_id == null) {
                    // search by nominatim
                    $subdistrict = Subdistrict::whereRaw('name ILIKE ?', ['%' . trim($addr_subdistrict) . '%'])
                    ->where("district_id", $district_id)
                    ->first();

                    // search by poscode
                    if ($subdistrict == null) {
                        $subdistrict = Subdistrict::whereRaw('name ILIKE ?', ['%' . trim($posCode->subdistrict) . '%'])
                        ->where("district_id", $district_id)
                        ->first();
                    }

                    $subdistrict_id = $posCode->subdistrict_id ?? $subdistrict->id ?? null;
                }

                
            }

            $address =  new Address([
                'label' => "",
                'name' => "",
                'address' => $address["road"] ?? $res["display_name"],
                'province_id' => $province_id,
                'city_id' => $city_id,
                'district_id' => $district_id,
                'subdistrict_id' => $subdistrict_id,
             
                'postal_code' => $address['postcode'],
                'phone' => "",
                'latitude' => $res['lat'],
                'longitude' => $res['lon'],
                'user_id' => auth()->user()->id,
                'is_primary' => false
            ]);
        } catch (ModelNotFoundException $e) {
          
            abort(404, 'lokasi tidak didukung');
        }

        return $address;
    }

    public function create($data)
    {
        $model = DB::transaction(function () use ($data) {

            $model = Address::create([
                'label' => $data['label'],
                'name' => $data['name'],
                'address' => $data['address'],
                'province_id' => $data['province_id'],
                'city_id' => $data['city_id'],
                'district_id' => $data['district_id'],
                'subdistrict_id' => $data['subdistrict_id'],
                'postal_code' => $data['postal_code'],
                'phone' => $data['phone'],
                'latitude' => $data['latitude'],
                'longitude' => $data['longitude'],
                'user_id' => auth()->user()->id,
                'is_primary' => $data['is_primary']
            ]);

            return $model;
        });

        return $model;
    }

    public function update($id ,$data)
    {
        $model = DB::transaction(function () use ($id, $data) {

            $model = Address::findOrFail($id);
            $model->label = $data['label'] ?? $model->label;
            $model->name = $data['name'] ?? $model->name;
            $model->address = $data['address'] ?? $model->address;
            $model->province_id = $data['province_id'] ?? $model->province_id;
            $model->city_id = $data['city_id'] ?? $model->city_id;
            $model->district_id = $data['district_id'] ?? $model->district_id;
            $model->subdistrict_id = $data['subdistrict_id'] ?? $model->subdistrict_id;
            $model->postal_code = $data['postal_code'] ?? $model->postal_code;
            $model->phone = $data['phone'] ?? $model->phone;
            $model->latitude = $data['latitude'] ?? $model->latitude;
            $model->longitude = $data['longitude'] ?? $model->longitude;
            $model->is_primary = $data['is_primary'] ?? $model->is_primary;
            $model->save();
            return $model;
        });

        return $model;
    }

    public function setPrimary($id)
    {
        $model = DB::transaction(function () use ($id) {

            $model = Address::findOrFail($id);

            Address::where("user_id", $model->user_id)->update([
                "is_primary" => 0
            ]);


            $model->is_primary = 1;
            $model->save();

            return $model;
        });

        return $model;
    }

    public function delete($model)
    {
        $model = DB::transaction(function () use ($model) {
            $model->delete();
            return $model;
        });

        return $model;
    }

    public function getProvince($request)
    {
        $model = Province::orderBy('name','desc')->where("is_new",true)->paginate($request->limit);

        return $model;
    }

    public function getCity($request)
    {
        $all = $request->all();

        $model = City::orderBy('name','desc')->where("is_new",true)
        ->where(function($query) use ($all){
            if (@$all["province_id"])
                $query->where("province_id", $all["province_id"]);
        })->paginate($request->limit);

        return $model;
    }

    public function getDistrict($request)
    {
        $all = $request->all();

        $model = District::orderBy('name','desc')->where("is_new",true)
        ->where(function($query) use ($all){
            if (@$all["city_id"])
                $query->where("city_id", $all["city_id"]);
        })->paginate($request->limit);

        return $model;
    }

    public function getSubdistrict($request)
    {
        $all = $request->all();
        $model = Subdistrict::orderBy('name','desc')->where("is_new",true)
            ->where(function($query) use ($all){
                if (@$all["district_id"])
                    $query->where("district_id", $all["district_id"]);
            })
            ->paginate($request->limit);

        return $model;
    }

    public function getPoscode($request)
    {

        $all = $request->all();
        $model = PosCode::orderBy('province','desc')
            ->where(function($query) use ($all){
                if (@$all["village"])
                    $query->where("village", $all["village"]);

                if (@$all["district"])
                    $query->where("district", $all["district"]);

                if (@$all["regency"])
                    $query->where("regency", $all["regency"]);
            })
            ->paginate($request->limit);

        return $model;
    }

}
