<?php

namespace Vendtics\App\Http\Controllers;

defined( "ABSPATH" ) || exit;

use Vendtics\App\Repositories\CampaignRepository;
use Vendtics\App\Repositories\CampaignRecipientRepository;
use Vendtics\App\Http\Controllers\Controller;
use Vendtics\WpMVC\Exceptions\Exception;
use Vendtics\WpMVC\Routing\Response;
use Vendtics\WpMVC\RequestValidator\Validator;
use Vendtics\App\Jobs\Campaign;
use Vendtics\App\Models\CampaignRecipient;
use Vendtics\App\Models\Campaign as CampaignModel;
use WP_REST_Request;

class CampaignJobController extends Controller {
    public CampaignRepository $campaign_repository;

    public CampaignRecipientRepository $campaign_recipient_repository;

    public function __construct( CampaignRepository $campaign_repository, CampaignRecipientRepository $campaign_recipient_repository ) {
        $this->campaign_repository           = $campaign_repository;
        $this->campaign_recipient_repository = $campaign_recipient_repository;
    }

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

        $campaign = $this->campaign_repository->get_by_id( intval( $request->get_param( 'id' ) ), ['id', 'name', 'status', 'type', 'schedule_time', 'recipient_type', 'segment_id', 'advanced_filters'] );

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

        $campaign_recipient = CampaignRecipient::query()->select(
            "COUNT(CASE WHEN opened_at IS NOT NULL THEN 1 END) AS open,
            COUNT(CASE WHEN clicked_at IS NOT NULL THEN 1 END) AS click,
            COUNT(CASE WHEN status = 'sent' THEN 1 END) AS sent,
            COUNT(CASE WHEN status = 'bounced' THEN 1 END) AS bounced,
            COUNT(CASE WHEN status = 'failed' THEN 1 END) AS failed",
        )->where( 'campaign_id', $campaign->id )->get();

        if ( 'schedule' === $campaign->status && current_time( 'mysql' ) > $campaign->schedule_time ) {
            $campaign->status = 'in_queue';
        }

        $totals             = map_deep( $campaign_recipient[0], 'intval' );
        $totals->recipients = $this->campaign_recipient_repository->get_recipient_query( $campaign )->distinct()->count( 'contact.id' );

        return Response::send(
            [
                "status" => $campaign->status,
                "name"   => $campaign->name,
                "type"   => $campaign->type,
                "totals" => $totals
            ]
        );
    }

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

        $campaign = $this->campaign_repository->get_by_id( intval( $request->get_param( 'id' ) ), ['id', 'status'] );

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

        if ( 'processing' !== $campaign->status ) {
            throw new Exception( esc_html__( "Sorry, the campaign is not processing", 'vendtics' ), 500 );
        }

        $this->campaign_repository->mark_as_paused( $campaign->id );

        $campaign_job = vendtics_singleton( Campaign::class );
        $campaign_job->cancel();

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

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

        $campaign = $this->campaign_repository->get_by_id( intval( $request->get_param( 'id' ) ), ['id', 'subject', 'body', 'status', 'type'] );

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

        if ( 'paused' !== $campaign->status ) {
            throw new Exception( esc_html__( "Sorry, the campaign is not paused", 'vendtics' ), 500 );
        }

        CampaignModel::query()->where( 'status', 'processing' )->update(
            [
                'status' => 'schedule'
            ]
        );

        $this->campaign_repository->mark_as_processing( $campaign->id );

        $campaign_job = vendtics_singleton( Campaign::class );

        if ( $campaign_job->is_processing() ) {
            $batches = $campaign_job->get_batches( 1 );

            if ( ! empty( $batches[0] ) ) {
                update_site_option(
                    $batches[0]->key, [
                        [
                            'campaign' => $campaign
                        ]
                    ]
                );
            } else {
                $campaign_job->push_to_queue(
                    [
                        'campaign' => $campaign
                    ]
                )->save()->dispatch();
            }
        } else {
            $campaign_job->push_to_queue(
                [
                    'campaign' => $campaign
                ]
            )->save()->dispatch();
        }

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

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

        $campaign = $this->campaign_repository->get_by_id( intval( $request->get_param( 'id' ) ), ['id', 'status'] );

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

        if ( ! in_array( $campaign->status, ['processing', 'paused'], true ) ) {
            throw new Exception( esc_html__( "Sorry, the campaign is not processing or paused", 'vendtics' ), 500 );
        }

        $campaign_job = vendtics_singleton( Campaign::class );
        $campaign_job->cancel();

        $this->campaign_repository->mark_as_cancel( $campaign->id, (string) $request->get_param( 'notes' ) );

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