<?php //phpcs:ignore Internal.Exception

namespace Vendtics\App\Repositories;

defined( "ABSPATH" ) || exit;

use Vendtics\WpMVC\Database\Query\Builder;
use Vendtics\WpMVC\Exceptions\Exception;
use Vendtics\App\Models\Tag;
use Vendtics\App\DTO\Contact\TagDTO;
use Vendtics\App\DTO\Contact\TagReadDTO;
use Vendtics\WpMVC\DTO\DTO;

class TagRepository extends Repository {
    public function get_query_builder(): Builder {
        return Tag::query( 'tag' );
    }

    public function get( TagReadDTO $dto ) {
        $query = $this->get_query_builder();

        $this->tag_search_query( $query, $dto );

        $count_query = clone $query;

        $this->tags_orders_query( $query, $dto )->select( 'tag.*' )->with_count(
            'contacts as total_contacts', function( $query ) {
                $query->where( 'entity_type', 'contacts' );
            } 
        );

        return [
            'tags'  => $query->pagination( $dto->get_page(), $dto->get_per_page() ),
            'total' => $count_query->count(),
        ];
    }

    protected function tag_search_query( Builder $query, TagReadDTO $dto ) {
        if ( ! $dto->is_initialized( 'search' ) ) {
            return $query;
        }

        $search = $dto->get_search();

        if ( empty( $search ) ) {
            return $query;
        }

        return $query->where(
            function( $like_query ) use( $search ) {
                $columns = [
                    'tag.name',
                    'tag.description'
                ];

                foreach ( $columns as $column ) {
                    $like_query->or_where_like( $column, "%{$search}%" );
                }
            }
        );
    }

    protected function tags_orders_query( Builder $query, TagReadDTO $dto ) {
        $order_columns =  [
            'id',
            'name',
            'description',
        ];

        if ( $dto->get_orders() ) {
            foreach ( $dto->get_orders() as $order ) {
                if ( empty( $order['order'] ) || empty( $order['order_by'] ) ) {
                    continue;
                }

                if ( ! in_array( $order['order_by'], $order_columns, true ) || ! in_array( $order['order'], ['asc', 'desc'], true ) ) {
                    continue;
                }

                $query->order_by( "tag.{$order['order_by']}", $order['order'] );
            }
        } else {
            $query->order_by( "tag.id", 'desc' );
        }

        return $query;
    }

    /**
     * @var TagDTO $dto
     */
    public function create( DTO $dto ) {
        /**
         * @var TagDTO $dto
         */
        $contact = $this->get_by( "name", $dto->get_name() );

        $this->throw_name_already_exists( $contact );

        return parent::create( $dto );
    }

     /**
     * @var TagDTO $dto
     */
    public function update( DTO $dto ) {
        /**
         * @var TagDTO $dto
         */
        $contact = $this->get_by_id( $dto->get_id() );

        if ( ! $contact ) {
            throw (new Exception( esc_html__( 'The tag not found.', 'vendtics' ), 404 ));
        }

        if ( $contact->name !== $dto->get_name() ) {
            $name_contact = $this->get_by( "name", $dto->get_name() );

            $this->throw_name_already_exists( $name_contact );
        }

        return parent::update( $dto );
    }

    private function throw_name_already_exists( $contact ) {
        if ( $contact ) {
            throw (new Exception( '', 422 ))->set_messages(
                [
                    "name" => [
                        esc_html__( "The name already exists.", 'vendtics' )
                    ]
                ]
            );
        }
    }

    public function select() {
        return Tag::query()->select( 'id', 'name' )->get();
    }

    public function count() {
        return Tag::query()->count();
    }
}