<?php

namespace HelpGent\App\Http\Controllers\Admin;

defined( 'ABSPATH' ) || exit;

use HelpGent\App\DTO\AdminEntryReadDTO;
use HelpGent\App\Http\Controllers\Controller;
use HelpGent\App\Repositories\ResponseRepository;
use HelpGent\WpMVC\Exceptions\Exception;
use HelpGent\WpMVC\RequestValidator\Validator;
use HelpGent\WpMVC\Routing\Response;
use WP_REST_Request;

class EntryController extends Controller {
    public ResponseRepository $repository;

    public function __construct( ResponseRepository $repository ) {
        $this->repository = $repository;
    }

    public function index( Validator $validator, WP_REST_Request $wp_rest_request ) {
        $validator->validate(
            [
                'form_id'    => 'string',
                'per_page'   => 'numeric',
                'page'       => 'numeric',
                'search'     => 'string|max:255',
                'status'     => 'string|accepted:all,read,unread,starred',
                'date_type'  => 'string|accepted:all,today,yesterday,last_week,last_month,date_frame',
                'date_frame' => 'array',
                'sort_by'    => 'string|accepted:submitted_on,form_name,status,submission',
                'sort_order' => 'string|accepted:asc,desc',
            ]
        );

        return Response::send( $this->repository->get_entries( $this->get_read_dto( $wp_rest_request ) ) );
    }

    public function count() {
        return Response::send(
            [
                'count' => $this->repository->get_new_entries_count(),
            ]
        );
    }

    public function export( Validator $validator, WP_REST_Request $wp_rest_request ) {
        $validator->validate(
            [
                'form_id'    => 'string',
                'search'     => 'string|max:255',
                'status'     => 'string|accepted:all,read,unread,starred',
                'date_type'  => 'string|accepted:all,today,yesterday,last_week,last_month,date_frame',
                'date_frame' => 'array',
                'sort_by'    => 'string|accepted:submitted_on,form_name,status,submission',
                'sort_order' => 'string|accepted:asc,desc',
            ]
        );

        $read_dto = $this->get_read_dto( $wp_rest_request );
        $entries  = $this->repository->export_entries( $read_dto );

        return Response::send(
            [
                'total'   => count( $entries ),
                'entries' => $entries,
                'forms'   => $this->repository->export_entry_forms( $read_dto ),
            ]
        );
    }

    public function update_read( Validator $validator, WP_REST_Request $wp_rest_request ) {
        $validator->validate(
            [
                'id'      => 'required|numeric',
                'is_read' => 'required|integer|accepted:0,1',
            ]
        );

        $response_id = intval( $wp_rest_request->get_param( 'id' ) );

        do_action( 'helpgent_before_update_entry_read', $response_id, $wp_rest_request, $validator );

        $this->repository->update_read( $response_id, intval( $wp_rest_request->get_param( 'is_read' ) ) );

        return Response::send(
            [
                'message' => esc_html__( 'Entry read status updated successfully.', 'helpgent' ),
            ]
        );
    }

    public function update_starred( Validator $validator, WP_REST_Request $wp_rest_request ) {
        $validator->validate(
            [
                'id'         => 'required|numeric',
                'is_starred' => 'required|integer|accepted:0,1',
            ]
        );

        $response_id = intval( $wp_rest_request->get_param( 'id' ) );

        do_action( 'helpgent_before_update_entry_starred', $response_id, $wp_rest_request, $validator );

        $this->repository->update_starred( $response_id, intval( $wp_rest_request->get_param( 'is_starred' ) ) );

        return Response::send(
            [
                'message' => esc_html__( 'Entry starred status updated successfully.', 'helpgent' ),
            ]
        );
    }

    public function bulk_update_read( Validator $validator, WP_REST_Request $wp_rest_request ) {
        $validator->validate(
            [
                'ids'     => 'required|array',
                'is_read' => 'required|integer|accepted:0,1',
            ]
        );

        $ids = $wp_rest_request->get_param( 'ids' );

        if ( empty( $ids ) || ! helpgent_is_one_level_array( $ids ) ) {
            throw new Exception( esc_html__( 'Entry ids must be a one-level array.', 'helpgent' ), 422 );
        }

        $ids = array_values( array_filter( array_map( 'absint', $ids ) ) );

        do_action( 'helpgent_before_bulk_update_entry_read', $ids, $wp_rest_request, $validator );

        $this->repository->update_bulk_read( $ids, intval( $wp_rest_request->get_param( 'is_read' ) ) );

        return Response::send(
            [
                'message' => esc_html__( 'Entries read status updated successfully.', 'helpgent' ),
            ]
        );
    }

    public function delete( Validator $validator, WP_REST_Request $wp_rest_request ) {
        $validator->validate(
            [
                'id' => 'required|numeric',
            ]
        );

        $response_id = intval( $wp_rest_request->get_param( 'id' ) );

        do_action( 'helpgent_before_delete_entry', $response_id, $wp_rest_request, $validator );

        $delete = $this->repository->delete( $response_id );

        if ( 0 === $delete ) {
            throw new Exception( esc_html__( 'Oops, something went wrong. Please try again.', 'helpgent' ), 500 );
        }

        return Response::send(
            [
                'message' => esc_html__( 'The entry has been deleted successfully.', 'helpgent' ),
            ]
        );
    }

    public function bulk_delete( Validator $validator, WP_REST_Request $wp_rest_request ) {
        $validator->validate(
            [
                'ids' => 'required|array',
            ]
        );

        $ids = $wp_rest_request->get_param( 'ids' );

        if ( empty( $ids ) || ! helpgent_is_one_level_array( $ids ) ) {
            throw new Exception( esc_html__( 'Entry ids must be a one-level array.', 'helpgent' ), 422 );
        }

        $ids = array_values( array_filter( array_map( 'absint', $ids ) ) );

        do_action( 'helpgent_before_bulk_delete_entry', $ids, $wp_rest_request, $validator );

        $delete = $this->repository->delete_bulk( $ids );

        if ( 0 === $delete ) {
            throw new Exception( esc_html__( 'Oops, something went wrong. Please try again.', 'helpgent' ), 500 );
        }

        return Response::send(
            [
                'message' => esc_html__( 'Entries have been deleted successfully.', 'helpgent' ),
            ]
        );
    }

    protected function get_read_dto( WP_REST_Request $wp_rest_request ): AdminEntryReadDTO {
        $form_id    = $wp_rest_request->get_param( 'form_id' );
        $date_frame = $wp_rest_request->get_param( 'date_frame' );

        return ( new AdminEntryReadDTO() )
            ->set_form_id( is_numeric( $form_id ) ? intval( $form_id ) : 0 )
            ->set_per_page( intval( $wp_rest_request->get_param( 'per_page' ) ) )
            ->set_page( intval( $wp_rest_request->get_param( 'page' ) ) )
            ->set_search( sanitize_text_field( (string) $wp_rest_request->get_param( 'search' ) ) )
            ->set_status( sanitize_text_field( (string) ( $wp_rest_request->get_param( 'status' ) ?: 'all' ) ) )
            ->set_date_type( sanitize_text_field( (string) ( $wp_rest_request->get_param( 'date_type' ) ?: 'all' ) ) )
            ->set_date_frame( is_array( $date_frame ) ? $date_frame : [] )
            ->set_sort_by( sanitize_text_field( (string) ( $wp_rest_request->get_param( 'sort_by' ) ?: 'submitted_on' ) ) )
            ->set_sort_order( sanitize_text_field( (string) ( $wp_rest_request->get_param( 'sort_order' ) ?: 'desc' ) ) );
    }
}
