<?php

/**
 * Event Category Api Class
 *
 * @package Eventin\Event
 */
namespace Eventin\EventCategory\Api;

defined( 'ABSPATH' ) || exit;

use Eventin\Event\CategoryExporter;
use Eventin\Event\CategoryImporter;
use WP_Error;
use WP_REST_Controller;
use WP_REST_Server;

/**
 * EventCategory Controller Class
 */
class EventCategoryController extends WP_REST_Controller {
    /**
     * Taxonomy key
     *
     * @var string
     */
    protected $taxonomy = 'etn_category';

    /**
     * Constructor for categoryController
     *
     * @return void
     */
    public function __construct() {
        $this->namespace = 'eventin/v2';
        $this->rest_base = 'event/categories';
    }

    /**
     * Check if a given request has access to get items.
     *
     * @param WP_REST_Request $request Full data about the request.
     * @return WP_Error|boolean
     */
    public function register_routes() {
        register_rest_route( $this->namespace, $this->rest_base, [
            [
                'methods'             => WP_REST_Server::READABLE,
                'callback'            => [$this, 'get_items'],
                'permission_callback' => [$this, 'get_item_permissions_check'],
            ],
            [
                'methods'             => WP_REST_Server::CREATABLE,
                'callback'            => [$this, 'create_item'],
                'permission_callback' => [$this, 'create_item_permissions_check'],
            ],
            [
                'methods'             => WP_REST_Server::DELETABLE,
                'callback'            => array( $this, 'delete_items' ),
                'permission_callback' => array( $this, 'update_item_permissions_check' ),
            ]
        ] );

        register_rest_route(
            $this->namespace,
            '/' . $this->rest_base . '/(?P<id>[\d]+)',
            array(
                'args' => array(
                    'id' => array(
                        'description' => __( 'Unique identifier for the post.', 'eventin' ),
                        'type'        => 'integer',
                    ),
                ),
                array(
                    'methods'             => WP_REST_Server::READABLE,
                    'callback'            => array( $this, 'get_item' ),
                    'permission_callback' => array( $this, 'get_item_permissions_check' ),
                    'args'                => $this->get_collection_params(),
                ),
                array(
                    'methods'             => WP_REST_Server::EDITABLE,
                    'callback'            => array( $this, 'update_item' ),
                    'permission_callback' => array( $this, 'update_item_permissions_check' ),
                    'args'                => $this->get_collection_params(),
                ),
                array(
                    'methods'             => WP_REST_Server::DELETABLE,
                    'callback'            => array( $this, 'delete_item' ),
                    'permission_callback' => array( $this, 'update_item_permissions_check' ),
                    'args'                => array(
                        'id' => array(
                            'description' => __( 'Unique identifier for the post.', 'eventin' ),
                            'type'        => 'integer',
                        ),
                    ),
                ),
            ),
        );

        // Export route
        register_rest_route(
            $this->namespace,
            '/' . $this->rest_base . '/export',
            array(
                array(
                    'methods'             => WP_REST_Server::CREATABLE,
                    'callback'            => array( $this, 'export_items' ),
                    'permission_callback' => array( $this, 'export_permissions_check' ),
                ),
            ),
        );

        // Import route
        register_rest_route(
            $this->namespace,
            '/' . $this->rest_base . '/import',
            array(
                array(
                    'methods'             => WP_REST_Server::CREATABLE,
                    'callback'            => array( $this, 'import_items' ),
                    'permission_callback' => array( $this, 'import_permissions_check' ),
                ),
            ),
        );
    }

    /**
     * Check if a given request has access to get items.
     *
     * @param WP_REST_Request $request Full data about the request.
     * @return WP_Error|boolean
     */
    public function get_item_permissions_check( $request ) {
        return current_user_can( 'etn_manage_event' );
    }

    /**
     * Get a collection of items.
     *
     * @param WP_REST_Request $request Full data about the request.
     * @return WP_Error|WP_REST_Response
     */
    public function get_items( $request ) {
        $per_page = ! empty( $request['per_page'] ) ? intval( $request['per_page'] ) : 20;
        $paged    = ! empty( $request['paged'] ) ? intval( $request['paged'] ) : 1;
        $offset   = ( $paged - 1 ) * $per_page;

        $prepared_args = array(
            'taxonomy'   => $this->taxonomy,
            'hide_empty' => false,
            'number'     => $per_page,
            'offset'     => $offset,
        );

        // Filter by parent category
        if ( isset( $request['parent'] ) && $request['parent'] !== '' ) {
            $prepared_args['parent'] = absint( $request['parent'] );
        }

        // Filter by search string
        if ( ! empty( $request['search'] ) ) {
            $prepared_args['search'] = sanitize_text_field( $request['search'] );
        }

        $query_result = get_terms( $prepared_args );

        // Get total count for pagination
        $count_args = $prepared_args;
        unset( $count_args['number'], $count_args['offset'] );
        $count_args['fields'] = 'count';
        $total_items = (int) get_terms( $count_args );

        $items = array();

        if ( ! is_wp_error( $query_result ) ) {
            foreach ( $query_result as $term ) {
                $item = $this->prepare_item_for_response( $term->term_id, $request );

                // Get the parent term name if the parent term exists
                if ( $term->parent ) {
                    $parent_term = get_term( $term->parent, $this->taxonomy );
                    if ( ! is_wp_error( $parent_term ) ) {
                        $item['parent_name'] = $parent_term->name;
                    } else {
                        $item['parent_name'] = null;
                    }
                } else {
                    $item['parent_name'] = null;
                }

                $items[] = $item;
            }
        }

        $total_pages = $per_page > 0 ? (int) ceil( $total_items / $per_page ) : 0;

        $data = [
            'total_items' => $total_items,
            'items'       => $items,
        ];

        $response = rest_ensure_response( $data );
        return $response;
    }

    /**
     * Get one item from the collection.
     *
     * @param WP_REST_Request $request Full data about the request.
     * @return WP_Error|WP_REST_Response
     */
    public function get_item( $request ) {
        $category = $this->get_category( $request['id'] );
        
        if ( is_wp_error( $category ) ) {
            return $category;
        }

        $response = $this->prepare_item_for_response( $request['id'], $request );

        return rest_ensure_response( $response );
    }

    /**
     * Create one item from the collection.
     *
     * @param WP_REST_Request $request Full data about the request.
     * @return WP_Error|WP_REST_Response
     */
    public function create_item( $request ) {
        $prepared_data = $this->prepare_item_for_database( $request );

        if ( is_wp_error( $prepared_data ) ) {
            return $prepared_data;
        }

        $category = wp_insert_term( $prepared_data['name'], $this->taxonomy, $prepared_data );
        if ( ! empty( $prepared_data['color'] ) ) {
            update_term_meta( $category['term_id'], 'color', sanitize_hex_color( $prepared_data['color'] ) );
        }
        if ( is_wp_error( $category ) ) {
            return $category;
        }

        $item = $this->prepare_item_for_response( $category['term_id'], $request );

        $respons = rest_ensure_response( $item );
        $respons->set_status( 201 );

        do_action( 'etn_category_created', $category['term_id'], json_decode( $request->get_body(), true ) );

        return $respons;
    }

    /**
     * Check if a given request has access to create items.
     *
     * @param WP_REST_Request $request Full data about the request.
     * @return WP_Error|boolean
     */
    public function create_item_permissions_check( $request ) {
        return current_user_can( 'etn_manage_event' );
    }

    /**
     * Update one item from the collection.
     *
     * @param WP_REST_Request $request Full data about the request.
     * @return WP_Error|WP_REST_Response
     */
    public function update_item( $request ) {
        $prepared_data = $this->prepare_item_for_database( $request );

        if ( is_wp_error( $prepared_data ) ) {
            return $prepared_data;
        }

        $category = wp_update_term( $request['id'], $this->taxonomy, $prepared_data );
        if ( ! empty( $prepared_data['color'] ) ) {
            update_term_meta( $category['term_id'], 'color', sanitize_hex_color( $prepared_data['color'] ) );
        }
        if ( is_wp_error( $category ) ) {
            return $category;
        }

        $item = $this->prepare_item_for_response( $category['term_id'], $request );

        $respons = rest_ensure_response( $item );

        do_action( 'etn_category_updated', $category['term_id'], json_decode( $request->get_body(), true ) );

        return $respons;
    }

    /**
     * Deletes an item from the database.
     *
     * @param array $request The request data containing the item ID.
     * @return WP_REST_Response|WP_Error The response indicating the success or failure of the deletion.
     */
    public function delete_item( $request ) {
        // Sanitize and validate the ID
        $id = sanitize_text_field( $request['id'] );
        if ( ! is_numeric( $id ) ) {
            return new WP_Error( 'rest_invalid_param', __( 'The term ID must be a number.', 'eventin' ), array( 'status' => 400 ) );
        }
    
        $term = get_term( $id, $this->taxonomy );
    
        if ( ! $term || is_wp_error( $term ) ) {
            return new WP_Error( 'rest_term_invalid', __( 'Term does not exist.', 'eventin' ), array( 'status' => 404 ) );
        }
    
        $deleted = wp_delete_term( $id, $this->taxonomy );
    
        if ( is_wp_error( $deleted ) ) {
            return $deleted;
        }
    
        if ( ! $deleted ) {
            return new WP_Error( 'rest_cannot_delete', __( 'The term cannot be deleted.', 'eventin' ), array( 'status' => 500 ) );
        }
    
        return new \WP_REST_Response( null, 204 );
    }

    /**
     * Bulk delete items.
     *
     * @param WP_REST_Request $request Full data about the request.
     * @return WP_REST_Response Response object.
     */
    public function delete_items( $request ) {
        $ids = ! empty( $request['ids'] ) ? $request['ids'] : [];

        if ( ! is_array( $ids ) ) {
            return new WP_Error(
                'rest_cannot_delete',
                __( 'Category ids must be an array.', 'eventin' ),
                array( 'status' => 400 )
            );
        }

        if ( ! $ids ) {
            return new WP_Error(
                'rest_cannot_delete',
                __( 'Category ids can not be empty.', 'eventin' ),
                array( 'status' => 400 )
            );
        }
        $count = 0;

        foreach ( $ids as $id ) {
            $deleted = wp_delete_term( $id, $this->taxonomy );

            if ( ! is_wp_error( $deleted ) ) {
                $count++;
            }
        }

        if ( $count == 0 ) {
            return new WP_Error(
                'rest_cannot_delete',
                __( 'Category cannot be deleted.', 'eventin' ),
                array( 'status' => 400 )
            );
        }

        // translators: %1$d is the number of categories deleted, %2$d is the total number of categories selected.
        $message = sprintf( __( '%1$d categories are deleted of %2$d', 'eventin' ), $count, count( $ids ) );

        return rest_ensure_response( $message );
    }

    /**
     * Check if a given request has access to update a specific item.
     *
     * @param WP_REST_Request $request Full data about the request.
     * @return WP_Error|boolean
     */
    public function update_item_permissions_check( $request ) {
        return current_user_can( 'etn_manage_event' );
    }

    /**
     * Get the category, if the ID is valid.
     *
     * @since 4.0.0
     *
     * @param int $id Supplied ID.
     * @return WP_Term|WP_Error category object if ID is valid, WP_Error otherwise.
     */
    protected function get_category( $id ) {
        $error = new WP_Error(
            'rest_category_invalid',
            __( 'Category does not exist.', 'eventin' ),
            array( 'status' => 404 )
        );

        if ( (int) $id <= 0 ) {
            return $error;
        }

        $term = get_term( (int) $id, $this->taxonomy );
        if ( empty( $term ) || $term->taxonomy !== $this->taxonomy ) {
            return $error;
        }

        return $term;
    }

    /**
     * Prepare the item for the REST response.
     *
     * @param mixed           $item WordPress representation of the item.
     * @param WP_REST_Request $request Request object.
     * @return WP_REST_Response $response
     */
    public function prepare_item_for_response( $category_id, $request ) {
        $item = get_term( $category_id, $this->taxonomy );

        $category_data = [
            'id'          => $item->term_id,
            'count'       => $item->count,
            'description' => $item->description,
            'link'        => get_term_link( $item ),
            'name'        => $item->name,
            'slug'        => $item->slug,
            'parent'      => $item->parent,
            'color'       => get_term_meta( $item->term_id, 'color', true ),
        ];

        return $category_data;
    }

    /**
     * Prepare data for database
     *
     * @param   WP_Rest_Request  $request
     *
     * @return  array
     */
    protected function prepare_item_for_database( $request ) {
        $input_data = json_decode( $request->get_body(), true );
        $validate   = etn_validate( $input_data, [
            'name' => [
                'required',
            ],
        ] );

        $prepared_data = [];

        if ( is_wp_error( $validate ) ) {
            return $validate;
        }

        if ( ! empty( $input_data['name'] ) ) {
            $prepared_data['name'] = $input_data['name'];
        }

        if ( ! empty( $input_data['description'] ) ) {
            $prepared_data['description'] = $input_data['description'];
        }

        if ( ! empty( $input_data['slug'] ) ) {
            $prepared_data['slug'] = $input_data['slug'];
        }

        if ( ! empty( $input_data['parent'] ) ) {
            $prepared_data['parent'] = $input_data['parent'];
        }
        if ( ! empty( $input_data['color'] ) ) {
            $prepared_data['color'] = sanitize_hex_color( $input_data['color'] );
        }

        return $prepared_data;
    }

    /**
     * Export categories
     *
     * @param WP_REST_Request $request Full data about the request.
     * @return WP_Error|void
     */
    public function export_items( $request ) {
        $format = ! empty( $request['format'] ) ? sanitize_text_field( $request['format'] ) : '';
        $ids    = ! empty( $request['ids'] ) ? $request['ids'] : '';

        if ( ! $format ) {
            return new WP_Error( 'format_error', __( 'Invalid data format', 'eventin' ), [ 'status' => 400 ] );
        }

        if ( ! $ids ) {
            $ids = CategoryExporter::get_ids();
        }

        $exporter = new CategoryExporter();
        $exporter->export( $ids, $format );
    }

    /**
     * Check permissions for export categories
     *
     * @param WP_REST_Request $request Full data about the request.
     * @return bool
     */
    public function export_permissions_check( $request ) {
        return current_user_can( 'etn_manage_event' );
    }

    /**
     * Import categories
     *
     * @param WP_REST_Request $request Full data about the request.
     * @return WP_Error|WP_REST_Response
     */
    public function import_items( $request ) {
        $data = $request->get_file_params();
        $file = ! empty( $data['category_import'] ) ? $data['category_import'] : '';

        if ( ! $file ) {
            return new WP_Error( 'empty_file', __( 'You must provide a valid file.', 'eventin' ), [ 'status' => 409 ] );
        }

        $importer = new CategoryImporter();
        $result   = $importer->import( $file );

        if ( is_wp_error( $result ) ) {
            return $result;
        }

        $response = [
            'message' => __( 'Successfully imported categories', 'eventin' ),
        ];

        return rest_ensure_response( $response );
    }

    /**
     * Check permissions for import categories
     *
     * @param WP_REST_Request $request Full data about the request.
     * @return bool
     */
    public function import_permissions_check( $request ) {
        return current_user_can( 'etn_manage_event' );
    }
}