<?php //phpcs:ignore Internal.Exception

namespace Vendtics\App\Http\Controllers\Admin;

defined( "ABSPATH" ) || exit;

use Vendtics\App\DTO\Contact\ContactDTO;
use Vendtics\App\Http\Controllers\Controller;
use Vendtics\WpMVC\Exceptions\Exception;
use Vendtics\WpMVC\Routing\Response;
use Vendtics\WpMVC\RequestValidator\Validator;
use Vendtics\App\Repositories\ContactRepository;
use Vendtics\App\DTO\Contact\ContactReadDTO;
use Vendtics\App\Repositories\ListRepository;
use Vendtics\App\Repositories\TagRepository;
use Vendtics\App\Repositories\SegmentRepository;
use Vendtics\App\Models\Contact;
use Vendtics\App\Services\DoubleOptIn;
use WP_REST_Request;

class ContactController extends Controller {
    public ContactRepository $repository;

    public SegmentRepository $segment_repository;

    public function __construct( ContactRepository $repository, SegmentRepository $segment_repository ) {
        $this->repository         = $repository;
        $this->segment_repository = $segment_repository;
    }

    /**
     * Display a listing of the resource.
     *
     * @param Validator $validator Instance of the Validator.
     * @param WP_REST_Request $request The REST request instance.
     * @return array
     */
    public function index( Validator $validator, WP_REST_Request $request ): array {
        $validator->validate(
            [
                'page'       => 'required|numeric',
                'per_page'   => 'required|numeric',
                'orders'     => 'json',
                'queries'    => 'json',
                'segment_id' => 'numeric'
            ]
        );

        $dto = ( new ContactReadDTO )
        ->set_page( intval( $request->get_param( 'page' ) ) )
        ->set_per_page( intval( $request->get_param( 'per_page' ) ) );

        if ( $request->has_param( 'orders' ) ) {
            $dto->set_orders( json_decode( $request->get_param( 'orders' ), true ) );
        }

        $this->bind_filter_queries( $dto, $request );

        return Response::send( $this->repository->get( $dto ) );
    }

    private function bind_filter_queries( ContactReadDTO $dto, WP_REST_Request $request ) {
        if ( $request->has_param( 'segment_id' ) ) {

            $segment = $this->segment_repository->get_by_id( $request->get_param( 'segment_id' ), 'queries' );

            if ( ! $segment ) {
                throw new Exception( esc_html__( "The segment not found", 'vendtics' ) );
            }

            return $dto->set_queries( json_decode( $segment->queries, true ) );
        }

        if ( $request->has_param( 'queries' ) ) {
            $dto->set_queries( json_decode( $request->get_param( 'queries' ), true ) );
        }

        return $dto;
    }

    /**
     * Store a newly created resource in storage.
     *
     * @param Validator $validator Instance of the Validator.
     * @param WP_REST_Request $request The REST request instance.
     * @return array
     */
    public function store( Validator $validator, WP_REST_Request $request ): array {
        // Define validation rules
        $validator->validate(
            [
                'first_name'    => 'string|max:50',
                'last_name'     => 'string|max:50',
                'email'         => 'required|email|max:100',
                'phone_number'  => 'string|max:20',
                'company'       => 'string|max:100',
                'designation'   => 'string|max:100',
                'date_of_birth' => 'date:Y-m-d',
                'timezone'      => 'string|max:50',
                'address'       => 'string|max:255',
                'city'          => 'string|max:100',
                'state'         => 'string|max:100',
                'postal_code'   => 'string|max:20',
                'country'       => 'string|max:100',
                'status'        => 'string|accepted:subscribe,pending,unsubscribe',
                'type'          => 'string|accepted:lead,customer',
                'tags'          => 'array',
                'lists'         => 'array',
                'double_optin'  => 'numeric|accepted:0,1'
            ]
        );

        $tags = $request->get_param( 'tags' );

        if ( is_array( $tags ) && ! vendtics_is_one_level_array( $tags ) ) {
            throw (new Exception( '', 422 ))->set_messages(
                [
                    "tags" => [
                        esc_html__( "Invalid tags.", 'vendtics' )
                    ]
                ]
            );
        }

        $lists = $request->get_param( 'lists' );

        if ( is_array( $lists ) && ! vendtics_is_one_level_array( $lists ) ) {
            throw (new Exception( '', 422 ))->set_messages(
                [
                    "lists" => [
                        esc_html__( "Invalid lists.", 'vendtics' )
                    ]
                ]
            );
        }

        do_action( 'vendtics_before_create_contact', $request, $validator );

        // Create DTO and set values
        $dto = new ContactDTO();
        $dto->set_first_name( $request->get_param( 'first_name' ) );
        $dto->set_last_name( $request->get_param( 'last_name' ) );
        $dto->set_email( $request->get_param( 'email' ) );
        $dto->set_phone_number( $request->get_param( 'phone_number' ) );
        $dto->set_company( $request->get_param( 'company' ) );
        $dto->set_designation( $request->get_param( 'designation' ) );
        $dto->set_date_of_birth( $request->get_param( 'date_of_birth' ) );
        $dto->set_timezone( $request->get_param( 'timezone' ) );
        $dto->set_address( $request->get_param( 'address' ) );
        $dto->set_city( $request->get_param( 'city' ) );
        $dto->set_state( $request->get_param( 'state' ) );
        $dto->set_postal_code( $request->get_param( 'postal_code' ) );
        $dto->set_country( $request->get_param( 'country' ) );
        $dto->set_status( $request->get_param( 'status' ) );
        $dto->set_type( $request->get_param( 'type' ) ?? 'customer' );
        $dto->set_tags( $tags );
        $dto->set_lists( $lists );

        // Store DTO in the repository
        $id = $this->repository->create( $dto );

        $dto->set_id( $id );

        if ( 'pending' === $dto->get_status() && 1 === intval( $request->get_param( 'double_optin' ) ) ) {
            vendtics_singleton( DoubleOptIn::class )->trigger( $id );
        }

        do_action( 'vendtics_after_create_contact', $dto, $request, $validator );

        return Response::send(
            [
                "message" => esc_html__( "The contact was created successfully", 'vendtics' ),
                "data"    => [
                    "id" => $id
                ]
            ], 201
        );
    }    

    /**
     * Display the specified resource.
     *
     * @param Validator $validator Instance of the Validator.
     * @param WP_REST_Request $request The REST request instance.
     * @return array
     * @throws Exception
     */
    public function show( Validator $validator, WP_REST_Request $request ): array {
        $validator->validate(
            [
                "id" => "required|numeric"
            ]
        );

        $contact = $this->repository->get_single( $request->get_param( "id" ) );

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

        $contact->avatar_url            = get_avatar_url( $contact->email );
        $contact->last_order_amount     = 0;
        $contact->lifetime_order_amount = 0;
        $contact->total_orders          = 0;

        return Response::send(
            [
                "data" => apply_filters( 'vendtics_single_contact', $contact )
            ]
        );
    }

    /**
     * Update the specified resource in storage.
     *
     * @param Validator $validator Instance of the Validator.
     * @param WP_REST_Request $request The REST request instance.
     * @return array
     */
    public function update( Validator $validator, WP_REST_Request $request ): array {
        // Define validation rules
        $validator->validate(
            [
                'id'            => 'required|numeric',
                'first_name'    => 'string|max:50',
                'last_name'     => 'string|max:50',
                'email'         => 'email|max:100',
                'phone_number'  => 'string|max:20',
                'company'       => 'string|max:100',
                'designation'   => 'string|max:100',
                'date_of_birth' => 'date:Y-m-d',
                'timezone'      => 'string|max:50',
                'address'       => 'string|max:255',
                'city'          => 'string|max:100',
                'state'         => 'string|max:100',
                'postal_code'   => 'string|max:20',
                'country'       => 'string|max:100',
                'status'        => 'string|max:20',
                'type'          => 'required|string|accepted:lead,customer',
                'tags'          => 'array',
                'lists'         => 'array',
                'double_optin'  => 'numeric|accepted:0,1'
            ]
        );

        $tags = $request->get_param( 'tags' );

        if ( is_array( $tags ) && ! vendtics_is_one_level_array( $tags ) ) {
            throw (new Exception( '', 422 ))->set_messages(
                [
                    "tags" => [
                        esc_html__( "Invalid tags.", 'vendtics' )
                    ]
                ]
            );
        }

        $lists = $request->get_param( 'lists' );

        if ( is_array( $lists ) && ! vendtics_is_one_level_array( $lists ) ) {
            throw (new Exception( '', 422 ))->set_messages(
                [
                    "lists" => [
                        esc_html__( "Invalid lists.", 'vendtics' )
                    ]
                ]
            );
        }

        do_action( 'vendtics_before_update_contact', $request, $validator );

        // Create DTO and set values
        $dto = new ContactDTO();
        $dto->set_id( $request->get_param( 'id' ) );
        $dto->set_first_name( $request->get_param( 'first_name' ) );
        $dto->set_last_name( $request->get_param( 'last_name' ) );
        $dto->set_email( $request->get_param( 'email' ) );
        $dto->set_phone_number( $request->get_param( 'phone_number' ) );
        $dto->set_company( $request->get_param( 'company' ) );
        $dto->set_designation( $request->get_param( 'designation' ) );
        $dto->set_date_of_birth( $request->get_param( 'date_of_birth' ) );
        $dto->set_timezone( $request->get_param( 'timezone' ) );
        $dto->set_address( $request->get_param( 'address' ) );
        $dto->set_city( $request->get_param( 'city' ) );
        $dto->set_state( $request->get_param( 'state' ) );
        $dto->set_postal_code( $request->get_param( 'postal_code' ) );
        $dto->set_country( $request->get_param( 'country' ) );
        $dto->set_status( $request->get_param( 'status' ) );
        $dto->set_type( $request->get_param( 'type' ) );
        $dto->set_tags( $tags );
        $dto->set_lists( $lists );

        // Update DTO in the repository
        $this->repository->update( $dto );

        if ( 'pending' === $dto->get_status() && 1 === intval( $request->get_param( 'double_optin' ) ) ) {
            vendtics_singleton( DoubleOptIn::class )->trigger( $dto->get_id() );
        }

        do_action( 'vendtics_after_update_contact', $dto, $request, $validator );

        $contact                        = $this->repository->get_single( $dto->get_id() );
        $contact->avatar_url            = get_avatar_url( $contact->email );
        $contact->last_order_amount     = 0;
        $contact->lifetime_order_amount = 0;
        $contact->total_orders          = 0;

        return Response::send(
            [
                'message' => esc_html__( 'The contact was updated successfully', 'vendtics' ),
                "data"    => apply_filters( 'vendtics_single_contact', $contact )
            ]
        );    
    }

    /**
     * Remove the specified resource from storage.
     *
     * @param Validator $validator Instance of the Validator.
     * @param WP_REST_Request $request The REST request instance.
     * @return array
     */
    public function delete( Validator $validator, WP_REST_Request $request ): array {
        $validator->validate(
            [
                "id" => "required|numeric"
            ]
        );

        $this->repository->delete_by_id( $request->get_param( "id" ) );

        return Response::send(
            [
                "message" => esc_html__( "The contact was deleted successfully", 'vendtics' )
            ]
        );
    }

    public function tabs_count(): array {
        $list_repository    = vendtics_singleton( ListRepository::class );
        $tag_repository     = vendtics_singleton( TagRepository::class );
        $segment_repository = vendtics_singleton( SegmentRepository::class );

        return Response::send(
            [
                "counts" => [
                    'contacts' => $this->repository->count(),
                    'lists'    => $list_repository->count(),
                    'tags'     => $tag_repository->count(),
                    'segments' => $segment_repository->count(),
                ]
            ]
        );
    }

    public function contact_count(): array {
        return Response::send(
            [
                "counts" => [
                    'all'         => $this->repository->count(),
                    'subscribe'   => $this->repository->total_subscriber(),
                    'unsubscribe' => $this->repository->total_unsubscriber(),
                    'pending'     => $this->repository->total_pending(),
                ]
            ]
        );
    }

    /**
     * @param Validator $validator Instance of the Validator.
     * @param WP_REST_Request $request The REST request instance.
     * @return array
     */
    public function bulk_delete( Validator $validator, WP_REST_Request $request ): array {
        $validator->validate(
            [
                "ids" => "required|array"
            ]
        );

        if ( ! vendtics_is_one_level_array( $request->get_param( 'ids' ) ) ) {
            throw new Exception( esc_html__( "Something was wrong", 'vendtics' ), 505 );
        }

        $ids = map_deep( $request->get_param( 'ids' ), "intval" );

        $this->repository->bulk_delete( $ids );

        return Response::send(
            [
                'message' => esc_html__( "The contact list was removed successfully!", 'vendtics' )
            ]
        );
    }

    /**
     * @param Validator $validator Instance of the Validator.
     * @param WP_REST_Request $request The REST request instance.
     * @return array
     */
    public function bulk_assign_tags( Validator $validator, WP_REST_Request $request ): array {
        $validator->validate(
            [
                "ids"     => "required|array",
                "tag_ids" => "required|array",
            ]
        );

        if ( ! vendtics_is_one_level_array( $request->get_param( 'ids' ) ) || ! vendtics_is_one_level_array( $request->get_param( 'tag_ids' ) ) ) {
            throw new Exception( esc_html__( "Something was wrong", 'vendtics' ), 505 );
        }

        $this->repository->bulk_assign_tags( Contact::query(), $request->get_param( 'ids' ), $request->get_param( 'tag_ids' ) );

        return Response::send(
            [
                'message' => esc_html__( "Tags assigned successfully!", 'vendtics' )
            ]
        );
    }

    /**
     * @param Validator $validator Instance of the Validator.
     * @param WP_REST_Request $request The REST request instance.
     * @return array
     */
    public function bulk_unassign_tags( Validator $validator, WP_REST_Request $request ): array {
        $validator->validate(
            [
                "ids"     => "required|array",
                "tag_ids" => "required|array",
            ]
        );

        if ( ! vendtics_is_one_level_array( $request->get_param( 'ids' ) ) || ! vendtics_is_one_level_array( $request->get_param( 'tag_ids' ) ) ) {
            throw new Exception( esc_html__( "Something was wrong", 'vendtics' ), 505 );
        }

        $this->repository->bulk_unassign_tags( $request->get_param( 'ids' ), $request->get_param( 'tag_ids' ) );

        return Response::send(
            [
                'message' => esc_html__( "Tags unassigned successfully!", 'vendtics' )
            ]
        );
    }

    /**
     * @param Validator $validator Instance of the Validator.
     * @param WP_REST_Request $request The REST request instance.
     * @return array
     */
    public function bulk_assign_lists( Validator $validator, WP_REST_Request $request ): array {
        $validator->validate(
            [
                "ids"      => "required|array",
                "list_ids" => "required|array",
            ]
        );

        if ( ! vendtics_is_one_level_array( $request->get_param( 'ids' ) ) || ! vendtics_is_one_level_array( $request->get_param( 'list_ids' ) ) ) {
            throw new Exception( esc_html__( "Something was wrong", 'vendtics' ), 505 );
        }

        $this->repository->bulk_assign_lists( Contact::query(), $request->get_param( 'ids' ), $request->get_param( 'list_ids' ) );

        return Response::send(
            [
                'message' => esc_html__( "Lists assigned successfully!", 'vendtics' )
            ]
        );
    }

    /**
     * @param Validator $validator Instance of the Validator.
     * @param WP_REST_Request $request The REST request instance.
     * @return array
     */
    public function bulk_unassign_lists( Validator $validator, WP_REST_Request $request ): array {
        $validator->validate(
            [
                "ids"      => "required|array",
                "list_ids" => "required|array",
            ]
        );

        if ( ! vendtics_is_one_level_array( $request->get_param( 'ids' ) ) || ! vendtics_is_one_level_array( $request->get_param( 'list_ids' ) ) ) {
            throw new Exception( esc_html__( "Something was wrong", 'vendtics' ), 505 );
        }

        $this->repository->bulk_unassign_lists( $request->get_param( 'ids' ), $request->get_param( 'list_ids' ) );

        return Response::send(
            [
                'message' => esc_html__( "Lists unassigned successfully!", 'vendtics' )
            ]
        );
    }

    /**
     * @param Validator $validator Instance of the Validator.
     * @param WP_REST_Request $request The REST request instance.
     * @return array
     */
    public function bulk_update_status( Validator $validator, WP_REST_Request $request ): array {
        $validator->validate(
            [
                "ids"    => "required|array",
                'status' => 'required|string|accepted:subscribe,pending,unsubscribe',
            ]
        );

        if ( ! vendtics_is_one_level_array( $request->get_param( 'ids' ) ) ) {
            throw new Exception( esc_html__( "Something was wrong", 'vendtics' ), 505 );
        }

        $dto = new ContactDTO;
        $dto->set_status( $request->get_param( 'status' ) );

        $this->repository->bulk_update( map_deep( $request->get_param( 'ids' ), "intval" ), $dto );

        return Response::send(
            [
                'message' => esc_html__( "Status update successfully!", 'vendtics' )
            ]
        );
    }

    /**
     * @param Validator $validator Instance of the Validator.
     * @param WP_REST_Request $request The REST request instance.
     * @return array
     */
    public function bulk_update_type( Validator $validator, WP_REST_Request $request ): array {
        $validator->validate(
            [
                "ids"  => "required|array",
                'type' => 'required|string|accepted:lead,customer',
            ]
        );

        if ( ! vendtics_is_one_level_array( $request->get_param( 'ids' ) ) ) {
            throw new Exception( esc_html__( "Something was wrong", 'vendtics' ), 505 );
        }

        $dto = new ContactDTO;
        $dto->set_type( $request->get_param( 'type' ) );

        $this->repository->bulk_update( map_deep( $request->get_param( 'ids' ), "intval" ), $dto );

        return Response::send(
            [
                'message' => esc_html__( "Type update successfully!", 'vendtics' )
            ]
        );
    }

    /**
     * @param Validator $validator Instance of the Validator.
     * @param WP_REST_Request $request The REST request instance.
     * @return array
     */
    public function update_status( Validator $validator, WP_REST_Request $request ): array {
        $validator->validate(
            [
                'id'     => 'required|numeric',
                'status' => 'required|string|accepted:subscribe,pending,unsubscribe'
            ]
        );

        $this->repository->update_status( intval( $request->get_param( 'id' ) ), $request->get_param( 'status' ) );

        return Response::send(
            [
                'message' => esc_html__( "The contact status was updated successfully!", 'vendtics' )
            ]
        );
    }

    /**
     * @param Validator $validator Instance of the Validator.
     * @param WP_REST_Request $request The REST request instance.
     * @return array
     */
    public function update_type( Validator $validator, WP_REST_Request $request ): array {
        $validator->validate(
            [
                'id'   => 'required|numeric',   
                'type' => 'required|string|accepted:lead,customer'
            ]
        );

        $this->repository->update_type( intval( $request->get_param( 'id' ) ), $request->get_param( 'type' ) );

        return Response::send(
            [
                'message' => esc_html__( "The contact type was updated successfully!", 'vendtics' )
            ]
        );
    }
}