<?php

namespace App\Repositories;

use App\Exceptions\Products\CreateProductInvalidArgumentException;
use App\Exceptions\Products\ProductNotFoundException;
use App\Models\Product;
use Illuminate\Database\Eloquent\ModelNotFoundException;
use Illuminate\Database\QueryException;

class ProductRepository
{
    public function __construct(Product $product)
    {
        $this->model = $product;
    }

    public function all()
    {
        return $this->model->all();
    }

    public function createOrUpdate(array $data, $update = false, $id = null)
    {
        try {
            $product = $update ? $this->model->find($id) : new $this->model;
            $product->name = $data['name'];
            $product->description = $data['description'];
            $product->category_id = $data['category_id'];
            // $product->price = $data['price'] ?? null;
            // $product->features = $data['features'] ?? null;
            // $product->dynamic_pricing = $data['dynamic_pricing'] ?? false;
            // $product->type = $data['type'] ?? 'simple';
            $product->user_id = $data['user_id'];
            $product->status = (isset($data['save'])) ? 0 : 1;

            if ($update) {
                $product->update();
            } else {
                $product->save();
            }

            if (isset($data['attachmentIds'])) {
                $product->syncMedia($data['attachmentIds'], 'attachments');
            }

            if (isset($data['plans'])) {
                for ($x = 0; $x < count($data['plans']['price']); $x++) {
                    $product->plans()->create([
                        'name' => $data['plans']['name'][$x] ?? null,
                        'description' => $data['plans']['description'][$x] ?? null,
                        'price' => $data['plans']['price'][$x] ?? null,
                        'features' => json_encode(explode('\n', $data['plans']['features'][$x])) ?? null,
                    ]);
                }
            }

            if (!empty($data['term_list'])) {

                $selected_cats = $data['term_list'];

                $terms = [];

                foreach ($selected_cats as $cat) {
                    $terms = array_merge($terms, get_term_parent_ids($cat));
                }

                $product->terms()->sync(array_unique($terms));
            }

            if (!empty($data['meta'])) {
                foreach ($data['meta'] as $key => $value) {
                    if ($key == 'attachments') {
                        $product->syncMedia($value, 'attachments');
                    } else {
                        $value = is_array($value) ? serialize($value) : $value;
                        $product->meta()->updateOrCreate(['key' => $key], ['value' => $value]);
                    }
                }
            }

            return $product;

        } catch (QueryException $e) {
            throw new CreateProductInvalidArgumentException($e->getMessage(), 500, $e);
        }
    }

    public function find($id)
    {
        try {
            return $this->model::with('meta')->findOrFail($id);
        } catch (ModelNotFoundException $ex) {
            throw new ProductNotFoundException($ex);
        }
    }

    public function paginate($perPage)
    {
        return $this->model->orderBy('id', 'desc')->paginate($perPage);
    }

    public function filter($searchTerm, $category_id, $perPage)
    {
        $query = $this->model::query();

        if ($searchTerm) {
            $query->where(function ($q) use ($searchTerm) {
                $q->where('name', 'LIKE', '%' . $searchTerm . '%');
            });
        }

        if ($category_id) {
            $query->where('category_id', $category_id);
        }

        return $query->paginate($perPage);
    }

    public function delete($id)
    {
        $this->deleteRow($id);

        return true;
    }

    public function deleteProducts($product_ids)
    {
        foreach ($product_ids as $id) {
            $this->deleteRow($id);
        }

        return true;
    }

    private function deleteRow($id)
    {
        $product = $this->find($id);

        $product->delete();
    }
}
