<?php
/**
 * Lead workflow repository.
 *
 * @package SubmissionInbox
 */

namespace SUBIN\Leads;

if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

// phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- Repository methods update Submission Inbox workflow fields directly.

/**
 * Manages pipeline fields on saved leads.
 */
class LeadWorkflowRepository {
	const WORKFLOW_OPEN      = 'open';
	const WORKFLOW_CONTACTED = 'contacted';
	const WORKFLOW_QUALIFIED = 'qualified';
	const WORKFLOW_WON       = 'won';
	const WORKFLOW_LOST      = 'lost';

	const PRIORITY_LOW    = 'low';
	const PRIORITY_NORMAL = 'normal';
	const PRIORITY_HIGH   = 'high';
	const PRIORITY_URGENT = 'urgent';

	/**
	 * Activity repository.
	 *
	 * @var LeadActivityRepository
	 */
	private $activity;

	/**
	 * Constructor.
	 *
	 * @param LeadActivityRepository|null $activity Activity repository.
	 */
	public function __construct( ?LeadActivityRepository $activity = null ) {
		$this->activity = $activity ? $activity : new LeadActivityRepository();
	}

	/**
	 * Workflow statuses.
	 *
	 * @return array<string,string>
	 */
	public function workflow_statuses() {
		return array(
			self::WORKFLOW_OPEN      => __( 'Open', 'submission-inbox' ),
			self::WORKFLOW_CONTACTED => __( 'Contacted', 'submission-inbox' ),
			self::WORKFLOW_QUALIFIED => __( 'Qualified', 'submission-inbox' ),
			self::WORKFLOW_WON       => __( 'Won', 'submission-inbox' ),
			self::WORKFLOW_LOST      => __( 'Lost', 'submission-inbox' ),
		);
	}

	/**
	 * Priorities.
	 *
	 * @return array<string,string>
	 */
	public function priorities() {
		return array(
			self::PRIORITY_LOW    => __( 'Low', 'submission-inbox' ),
			self::PRIORITY_NORMAL => __( 'Normal', 'submission-inbox' ),
			self::PRIORITY_HIGH   => __( 'High', 'submission-inbox' ),
			self::PRIORITY_URGENT => __( 'Urgent', 'submission-inbox' ),
		);
	}

	/**
	 * Update workflow fields.
	 *
	 * @param int                 $lead_id Lead id.
	 * @param array<string,mixed> $data Workflow data.
	 * @param int                 $actor_user_id Actor user id.
	 * @return bool
	 */
	public function update_workflow( $lead_id, array $data, $actor_user_id = 0 ) {
		global $wpdb;

		$lead_id = absint( $lead_id );
		if ( $lead_id <= 0 ) {
			return false;
		}

		$updates = array();
		$formats = array();

		if ( array_key_exists( 'workflow_status', $data ) ) {
			$updates['workflow_status'] = $this->sanitize_workflow_status( $data['workflow_status'] );
			$formats[] = '%s';
		}
		if ( array_key_exists( 'priority', $data ) ) {
			$updates['priority'] = $this->sanitize_priority( $data['priority'] );
			$formats[] = '%s';
		}
		if ( array_key_exists( 'assigned_user_id', $data ) ) {
			$updates['assigned_user_id'] = absint( $data['assigned_user_id'] );
			$formats[] = '%d';
		}
		if ( array_key_exists( 'follow_up_at', $data ) ) {
			$updates['follow_up_at'] = $this->sanitize_follow_up_at( $data['follow_up_at'] );
			$formats[] = '%s';
		}

		if ( empty( $updates ) ) {
			return false;
		}

		$updates['updated_at'] = current_time( 'mysql' );
		$formats[] = '%s';

		$result = $wpdb->update(
			$wpdb->prefix . 'subin_leads',
			$updates,
			array( 'id' => $lead_id ),
			$formats,
			array( '%d' )
		);

		if ( false === $result ) {
			return false;
		}

		$this->activity->add_activity(
			$lead_id,
			'workflow_updated',
			__( 'Workflow updated.', 'submission-inbox' ),
			$updates,
			$actor_user_id
		);
		do_action( 'subin_lead_workflow_updated', $lead_id, $updates );

		return true;
	}

	/**
	 * Sanitize workflow status.
	 *
	 * @param mixed $status Status.
	 * @return string
	 */
	public function sanitize_workflow_status( $status ) {
		$status = sanitize_key( (string) $status );

		return array_key_exists( $status, $this->workflow_statuses() ) ? $status : self::WORKFLOW_OPEN;
	}

	/**
	 * Sanitize priority.
	 *
	 * @param mixed $priority Priority.
	 * @return string
	 */
	public function sanitize_priority( $priority ) {
		$priority = sanitize_key( (string) $priority );

		return array_key_exists( $priority, $this->priorities() ) ? $priority : self::PRIORITY_NORMAL;
	}

	/**
	 * Sanitize follow-up date into mysql datetime.
	 *
	 * @param mixed $value Raw value.
	 * @return string|null
	 */
	public function sanitize_follow_up_at( $value ) {
		$value = sanitize_text_field( (string) $value );
		if ( '' === $value ) {
			return null;
		}

		if ( 1 === preg_match( '/^\d{4}-\d{2}-\d{2}$/', $value ) ) {
			return $value . ' 09:00:00';
		}

		return null;
	}
}
