<?php //phpcs:ignore Internal.Exception

namespace Vendtics\App\Http\Controllers\Admin;

defined( "ABSPATH" ) || exit;

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\CampaignRepository;
use Vendtics\App\DTO\Campaign\Read;
use Vendtics\App\DTO\Campaign\DTO;
use Vendtics\WpMVC\View\View;
use WP_REST_Request;

class CampaignController extends Controller {
    public CampaignRepository $repository;

    public function __construct( CampaignRepository $repository ) {
        $this->repository = $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',
                'type'     => 'string|accepted:standard,recurring,split,sequence',
                'orders'   => 'json'
            ]
        );

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

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

        return Response::send( $this->repository->get( $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 {
        // $this->validate(
        //     $validator, $request, [
        //         'type' => 'required|string|accepted:standard,split,recurring,sequence'
        //     ] 
        // );

        $validator->validate(
            [
                'name' => 'required|string|max:255',
                'type' => 'required|string|accepted:standard'
            ]
        );

        // if ( 'standard' !== $request->get_param( 'type' ) ) {
        //     $validator->validate( ['children' => 'required|array'] );

        //     $this->validate_children( $validator, $request );
        // }

        
        $dto = ( new DTO )->set_name( $request->get_param( 'name' ) )->set_type( $request->get_param( 'type' ) )->set_created_by( get_current_user_id() );
        $id  = $this->repository->create( $dto );

        // if ( 'standard' !== $request->get_param( 'type' ) ) {
        //     $this->repository->create_multiple( $this->get_children_dtos( $id, $request, true )->dtos );
        // }

        return Response::send(
            [
                "message" => esc_html__( "Campaign 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"
            ]
        );

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

        if ( ! $campaign ) {
            throw new Exception( esc_html__( "Campaign not found", 'vendtics' ) );
        }
        
        if ( ! empty( $campaign->utm_parameters ) ) {
            $campaign->utm_parameters = json_decode( $campaign->utm_parameters );
        }
        
        if ( ! empty( $campaign->advanced_filters ) ) {
            $campaign->advanced_filters = json_decode( $campaign->advanced_filters );
        }

        $campaign->html = View::get( 'classic-email', [ 'body' => $campaign->body ] );

        return Response::send(
            [
                "data" => $campaign
            ]
        );
    }

    /**
     * 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 {
        $this->validate( $validator, $request );

        $campaign = $this->repository->get_by_id( $request->get_param( 'id' ) );

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

        if ( 'standard' !== $campaign->type ) {
            $validator->validate( ['children' => 'required|array'] );

            $this->validate_children( $validator, $request, true );
        }

        $this->repository->update( $this->get_dto( $request ) );

        if ( 'standard' !== $campaign->type ) {
            $children = $this->get_children_dtos( $campaign->id, $request );

            if ( ! empty( $children->dtos ) ) {
                $this->repository->create_multiple( $children->dtos );
            }

            foreach ( $children->existing_dtos as $children_dto ) {
                $this->repository->update_children( $campaign->id, $children_dto );
            }
        }

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

    protected function validate( Validator $validator, WP_REST_Request $request, array $rules = [] ) {
        $validator->validate(
            array_merge(
                [
                    'name'                => 'required|string|max:255',
                    'subject'             => 'required|string|max:255',
                    'pre_header'          => 'required|string|max:255',
                    'utm_parameters'      => 'array',
                    'body'                => 'required|string',
                    'recipient_type'      => 'required|string|accepted:lists_tags,segment,advanced_filter',
                    'tracking_open_read'  => 'required|accepted:0,1',
                    'tracking_link_click' => 'required|accepted:0,1',
                ], $rules
            )
        );

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

        switch ( $recipient_type ) {
            case 'lists_tags':
                $validator->validate(
                    [
                        'tags'  => 'required|array',
                        'lists' => 'required|array'
                    ]
                );

                $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' )
                            ]
                        ]
                    );
                }
        
                break;
            case 'segment':
                $validator->validate(
                    [
                        'segment_id' => 'required|integer'
                    ]
                );
                break;
            case 'advanced_filter':
                $validator->validate(
                    [
                        'advanced_filters' => 'required|array'
                    ]
                );
        }
    }

    protected function validate_children( Validator $validator, WP_REST_Request $request, $id = false ) {
        $children_errors = [];

        $rules = [
            'name'           => 'required|string|max:255',
            'subject'        => 'string|max:255',
            'pre_header'     => 'string|max:255',
            'utm_parameters' => 'array',
            'body'           => 'string',
        ];

        if ( $id ) {
            $rules['id'] = 'integer';
        }

        foreach ( $request->get_param( 'children' ) as $value ) {
            $children_request = new WP_REST_Request( 'post', '/' );
            $children_request->set_body_params( $value );

            $validator->wp_rest_request = $children_request;

            $validator->validate( $rules, false );

            if ( $validator->is_fail() ) {
                $children_errors[] = $validator->errors;
            }
        }

        if ( ! empty( $children_errors ) ) {
            throw (new Exception( '', 422 ))->set_messages(
                [
                    'children' => $children_errors
                ]
            );
        }

        $validator->wp_rest_request = $request;
    }

    protected function get_dto( WP_REST_Request $request, bool $is_new = false ) {
        $recipient_type = $request->get_param( 'recipient_type' );

        $dto = ( new DTO )->set_name( $request->get_param( 'name' ) )
        ->set_subject( $request->get_param( 'subject' ) )
        ->set_pre_header( $request->get_param( 'pre_header' ) )
        ->set_utm_parameters( $request->get_param( 'utm_parameters' ) )
        ->set_body( $request->get_param( 'body' ) )
        ->set_recipient_type( $request->get_param( 'recipient_type' ) )
        ->set_tracking_open_read( $request->get_param( 'tracking_open_read' ) )
        ->set_tracking_link_click( $request->get_param( 'tracking_link_click' ) );

        switch ( $recipient_type ) {
            case 'lists_tags':
                $dto->set_tags( $request->get_param( 'tags' ) )->set_lists( $request->get_param( 'lists' ) )
                
                ->set_segment_id( null )->set_advanced_filters( null );
                break;
            case 'segment':
                $dto->set_segment_id( $request->get_param( 'segment_id' ) )
                
                ->set_tags( [] )->set_lists( [] )->set_advanced_filters( null );
                break;
            case 'advanced_filter':
                $dto->set_advanced_filters( $request->get_param( 'advanced_filters' ) )
                
                ->set_segment_id( null )->set_tags( [] )->set_lists( [] );
        }

        if ( ! $is_new ) {
            $dto->set_id( intval( $request->get_param( 'id' ) ) );
        } else {
            $dto->set_type( $request->get_param( 'type' ) )->set_created_by( get_current_user_id() );
        }

        return $dto;
    }

    protected function get_children_dtos( int $parent_id, WP_REST_Request $request, bool $is_new = false ) {
        $dtos          = [];
        $existing_dtos = [];

        foreach ( $request->get_param( 'children' ) as $value ) {
            $children_request = new WP_REST_Request( 'post', '/' );
            $children_request->set_body_params( $value );

            $dto = ( new DTO )->set_name( $children_request->get_param( 'name' ) );

            if ( $children_request->has_param( 'subject' ) ) {
                $dto->set_subject( $children_request->get_param( 'subject' ) );
            }

            if ( $children_request->has_param( 'pre_header' ) ) {
                $dto->set_pre_header( $children_request->get_param( 'pre_header' ) );
            }

            if ( $children_request->has_param( 'utm_parameters' ) ) {
                $dto->set_utm_parameters( $children_request->get_param( 'utm_parameters' ) );
            }

            if ( $children_request->has_param( 'body' ) ) {
                $dto->set_body( $children_request->get_param( 'body' ) );
            }

            if ( $is_new ) {
                $dtos[] = $dto->set_type( 'children' )->set_parent_id( $parent_id )->set_created_by( get_current_user_id() );
            } else {
                if ( $children_request->has_param( 'id' ) ) {
                    $existing_dtos[] = $dto->set_id( intval( $children_request->get_param( 'id' ) ) );
                } else {
                    $dtos[] = $dto->set_type( 'children' )->set_parent_id( $parent_id )->set_created_by( get_current_user_id() );
                }
            }
        }

        return (object) compact( 'dtos', 'existing_dtos' );
    }

    /**
     * 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__( "Campaign was deleted successfully", 'vendtics' )
            ]
        );
    }

    /**
     * @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__( "Campaigns was removed successfully!", 'vendtics' )
            ]
        );
    }

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

        $this->repository->mark_as_draft( absint( $request->get_param( 'id' ) ) );

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

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

        $this->repository->mark_as_schedule( absint( $request->get_param( 'id' ) ), $request->get_param( 'schedule_time' ) );

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

    /**
     * @param Validator $validator Instance of the Validator.
     * @param WP_REST_Request $request The REST request instance.
     * @return array
     */
    public function send_right_now( Validator $validator, WP_REST_Request $request ): array {
        $validator->validate(
            [

                "id" => "required|numeric"
            ]
        );

        $this->repository->mark_as_schedule( absint( $request->get_param( 'id' ) ), current_time( 'mysql' ) );

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

    /**
     * @param Validator $validator Instance of the Validator.
     * @param WP_REST_Request $request The REST request instance.
     * @return array
     */
    public function update_name( Validator $validator, WP_REST_Request $request ): array {
        $validator->validate(
            [

                "id"   => "required|numeric",
                'name' => 'required|string|max:255'
            ]
        );

        $this->repository->update_name( absint( $request->get_param( 'id' ) ), $request->get_param( 'name' ) );

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

    public function campaigns_count(): array {
        return Response::send(
            [
                "counts" => [
                    'total_campaigns' => 10,
                    'revenue'         => 20,
                    'subscriber'      => 30,
                    'unsubscribed'    => 40
                ]
            ]
        );
    }
}