<?php

namespace IGD;

defined( 'ABSPATH' ) || exit;

class Proofing {

	/**
	 * Singleton instance.
	 *
	 * @var self|null
	 */
	protected static $instance = null;

	/**
	 * DB table name.
	 *
	 * @var string
	 */
	private $table;

	/**
	 * Constructor.
	 */
	private function __construct() {
		global $wpdb;
		$this->table = $wpdb->prefix . 'integrate_google_drive_selections';

		// Ajax
		add_action( 'wp_ajax_igd_get_selections', [ $this, 'get_selections_callback' ] );
		add_action( 'wp_ajax_igd_delete_selection', [ $this, 'delete_selection' ] );
		add_action( 'wp_ajax_igd_delete_proof_submissions', [ $this, 'delete_submissions' ] );
		add_action( 'wp_ajax_igd_mark_selection_as_read', [ $this, 'change_submission_status' ] );

		add_action( 'wp_ajax_igd_email_required', [ $this, 'handle_email_required' ] );
		add_action( 'wp_ajax_nopriv_igd_email_required', [ $this, 'handle_email_required' ] );

		add_action( 'wp_ajax_igd_photo_proof', [ $this, 'handle_proof_submission' ] );
		add_action( 'wp_ajax_nopriv_igd_photo_proof', [ $this, 'handle_proof_submission' ] );

		add_action( 'wp_ajax_igd_proof_download', [ $this, 'proof_download' ] );
		add_action( 'wp_ajax_nopriv_igd_proof_download', [ $this, 'proof_download' ] );

		// Add selections to localize data
		add_filter( 'igd_localize_data', [ $this, 'localize_data' ], 10, 2 );
	}

	public function localize_data( $data, $hook ) {

		global $current_screen;

		if ( is_object( $current_screen ) && 'google-drive_page_integrate-google-drive-proofing-submissions' === $current_screen->id ) {
			$data['selections'] = $this->get_selections();
		}

		return $data;

	}

	public function get_selections( array $args = [] ): array {
		global $wpdb;

		$where  = [];
		$values = [];

		$map = [
			'id'           => '%d',
			'shortcode_id' => '%d',
			'user_id'      => '%d',
			'email'        => '%s',
		];

		foreach ( $map as $key => $format ) {
			if ( isset( $args[ $key ] ) ) {
				$where[]  = "{$key} = {$format}";
				$values[] = $args[ $key ];
			}
		}

		$sql = "SELECT * FROM {$this->table}";
		if ( $where ) {
			$sql .= ' WHERE ' . implode( ' AND ', $where );
		}

		// Order by newest first
		$sql .= ' ORDER BY id DESC';

		$rows = $values
			? $wpdb->get_results( $wpdb->prepare( $sql, ...$values ), ARRAY_A )
			: $wpdb->get_results( $sql, ARRAY_A );

		return $this->hydrate_selections( $rows );
	}

	public function get_selections_callback() {
		Ajax::instance()->check_nonce();

		wp_send_json_success( $this->get_selections() );
	}

	private function normalize_files( array $selected ): array {
		$files = [];

		foreach ( $selected as $file ) {
			$files[] = [
				'id'            => $file['id'],
				'accountId'     => $file['accountId'],
				'name'          => $file['name'],
				'description'   => $file['description'],
				'size'          => $file['size'],
				'type'          => $file['type'],
				'extension'     => $file['extension'],
				'thumbnailLink' => $file['thumbnailLink'],
				'iconLink'      => $file['iconLink'],
				'webViewLink'   => $file['webViewLink'],
				'reviewTag'     => $file['reviewTag'] ?? '',
				'permissions'   => $file['permissions'],
			];
		}

		return $files;
	}

	private function hydrate_selections( array $rows ): array {

		foreach ( $rows as &$row ) {

			$row['files'] = maybe_unserialize( $row['files'] );

			// User
			if ( ! empty( $row['user_id'] ) && ( $user = get_userdata( $row['user_id'] ) ) ) {
				$row['user'] = [
					'id'    => $user->ID,
					'name'  => $user->display_name,
					'email' => $user->user_email,
				];
			} else {
				$row['user'] = [
					'id'    => '',
					'name'  => '',
					'email' => $row['email'],
				];
			}

			// Module
			$shortcode = Shortcode::get_shortcode_data( $row['shortcode_id'] );

			$row['module'] = [
				'id'    => $row['shortcode_id'],
				'title' => $shortcode['title'] ?? '',
				'type'  => $shortcode['type'] ?? '',
			];
		}

		return $rows;
	}

	/* -------------------------------------------------------------------------
	 * Ajax: Status / Delete
	 * ---------------------------------------------------------------------- */

	public function change_submission_status() {
		Ajax::instance()->check_nonce();

		$id = ! empty( $_REQUEST['id'] ) ? (int) $_REQUEST['id'] : 0;

		global $wpdb;

		$updated = $wpdb->update(
			$this->table,
			[ 'status' => 1 ],
			[ 'id' => $id ],
			[ '%d' ],
			[ '%d' ]
		);

		$updated !== false
			? wp_send_json_success()
			: wp_send_json_error();
	}

	public function delete_selection() {

		Ajax::instance()->check_nonce();

		$id = ! empty( $_REQUEST['id'] ) ? (int) $_REQUEST['id'] : 0;

		global $wpdb;

		$deleted = $wpdb->delete(
			$this->table,
			[ 'id' => $id ],
			[ '%d' ]
		);

		$deleted
			? wp_send_json_success()
			: wp_send_json_error();
	}

	public function delete_submissions() {

		Ajax::instance()->check_nonce();

		$ids = ! empty( $_REQUEST['ids'] ) ? Helpers::sanitize_array( $_REQUEST['ids'] ) : [];

		global $wpdb;

		$placeholders = implode( ',', array_fill( 0, count( $ids ), '%d' ) );
		$deleted      = $wpdb->query(
			$wpdb->prepare(
				"DELETE FROM {$this->table} WHERE id IN ({$placeholders})",
				...$ids
			)
		);

		$deleted !== false
			? wp_send_json_success()
			: wp_send_json_error();

	}

	/* -------------------------------------------------------------------------
	 * Email Required
	 * ---------------------------------------------------------------------- */

	public function handle_email_required() {
		Ajax::instance()->check_nonce();

		Ajax::instance()->set_current_shortcode_data();

		$shortcode_id = sanitize_text_field( $_POST['shortcodeId'] ?? '' );
		$email        = sanitize_email( $_POST['email'] ?? '' );

		if ( ! is_email( $email ) ) {
			wp_send_json_error( __( 'Invalid email address.', 'integrate-google-drive' ) );
		}

		setcookie( 'igd_user_email', $email, [
			'expires'  => 0,
			'path'     => COOKIEPATH,
			'domain'   => COOKIE_DOMAIN,
			'secure'   => is_ssl(),
			'httponly' => true,
			'samesite' => 'Strict',
		] );

		$_COOKIE['igd_user_email'] = $email;

		$shortcode_data = Shortcode::get_shortcode_data( $shortcode_id, true );

		$selection = $this->get_selections( [
			'email'        => $email,
			'shortcode_id' => $shortcode_id,
		] );

		if ( $selection ) {
			$shortcode_data['selection'] = reset( $selection );
		}

		$content = Shortcode::instance()->render_shortcode( [], $shortcode_data );
		wp_send_json_success( $content );
	}

	/* -------------------------------------------------------------------------
	 * Proof Submission
	 * ---------------------------------------------------------------------- */

	public function handle_proof_submission() {

		Ajax::instance()->check_nonce();

		$shortcode_id = sanitize_text_field( $_REQUEST['shortcodeId'] ?? '' );
		if ( empty( $shortcode_id ) ) {
			wp_send_json_error( __( 'Invalid shortcode ID', 'integrate-google-drive' ) );
		}

		Ajax::instance()->set_current_shortcode_data();

		$selection = ! empty( $_POST['selection'] ) ? Helpers::sanitize_array( $_POST['selection'] ) : false;
		$selected  = ! empty( $_POST['selected'] ) ? Helpers::sanitize_array( $_POST['selected'] ) : [];
		$message   = sanitize_textarea_field( $_POST['message'] ?? '' );

		// User
		$user = [ 'id' => '', 'name' => '', 'email' => '' ];

		if ( ! empty( $selection['user'] ) ) {
			$user = $selection['user'];
		} elseif ( is_user_logged_in() ) {
			$u    = wp_get_current_user();
			$user = [
				'id'    => $u->ID,
				'name'  => $u->display_name,
				'email' => $u->user_email,
			];
		} elseif ( isset( $_COOKIE['igd_user_email'] ) ) {
			$user['email'] = sanitize_email( $_COOKIE['igd_user_email'] );
		}

		$selection_id = $this->insert_selection(
			$shortcode_id,
			$selected,
			$user,
			$message,
			$selection
		);

		$shortcode_data = Shortcode::get_shortcode_data( $shortcode_id, true );

		// Send notification email if enabled
		if ( ! empty( $shortcode_data['notifications'] ) && ! empty( $shortcode_data['notifications']['proofNotification'] ) ) {

			$shortcode_title = $shortcode_data['title'];
			$shortcode_type  = $shortcode_data['type'];

			$recipients        = Notifications::get_recipients( $shortcode_data['notifications'], $shortcode_data['folders'] );
			$primary_recipient = $recipients[0] ?? get_bloginfo( 'admin_email' );
			$bcc               = implode( ',', array_slice( $recipients, 1 ) );

			$subject = $selection
				? sprintf( __( 'Proof selection has been updated for the "%s" module', 'integrate-google-drive' ), $shortcode_title )
				: sprintf( __( 'New proof selection submitted for the "%s" module', 'integrate-google-drive' ), $shortcode_title );

			ob_start();
			include trailingslashit( IGD_PATH ) . 'templates/photo-proof-email.php';
			$content = ob_get_clean();

			$headers = [
				'Content-Type: text/html; charset=UTF-8',
				'From: ' . sprintf( '%s <%s>', get_bloginfo( 'name' ), get_bloginfo( 'admin_email' ) ),
			];

			if ( ! empty( $user['email'] ) ) {
				$headers[] = 'Reply-To: ' . $user['email'];
			}
			if ( ! empty( $bcc ) ) {
				$headers[] = 'Bcc: ' . $bcc;
			}

			wp_mail( $primary_recipient, $subject, $content, $headers );
		}

		wp_send_json_success( $selection_id );
	}

	/* -------------------------------------------------------------------------
	 * CSV Download
	 * ---------------------------------------------------------------------- */

	public function proof_download() {

		if (
			empty( $_REQUEST['nonce'] ) ||
			! wp_verify_nonce( $_REQUEST['nonce'], 'igd_photo_proof_download' )
		) {
			wp_send_json_error( __( 'Invalid nonce', 'integrate-google-drive' ) );
		}

		$selection_id = (int) ( $_REQUEST['selection_id'] ?? 0 );
		if ( ! $selection_id ) {
			wp_send_json_error( __( 'Invalid selection ID', 'integrate-google-drive' ) );
		}

		$selection = $this->get_selections( [ 'id' => $selection_id ] );
		if ( empty( $selection ) ) {
			wp_send_json_error( __( 'Selection not found', 'integrate-google-drive' ) );
		}

		$selection = $selection[0];
		$files     = $selection['files'] ?? [];

		header( 'Content-Type: text/csv; charset=utf-8' );
		header( "Content-Disposition: attachment; filename=selection-{$selection_id}.csv" );

		$out = fopen( 'php://output', 'w' );

		fputcsv( $out, [
			'Selection ID',
			'Shortcode ID',
			'User ID',
			'User Name',
			'User Email',
			'Message',
			'Date',
			'File ID',
			'File Name',
			'File Description',
			'Tag',
			'File URL',
		] );

		foreach ( $files as $i => $file ) {
			fputcsv( $out, [
				$i === 0 ? $selection['id'] : '',
				$i === 0 ? $selection['shortcode_id'] : '',
				$i === 0 ? ( $selection['user']['id'] ?? '' ) : '',
				$i === 0 ? ( $selection['user']['name'] ?? '' ) : '',
				$i === 0 ? ( $selection['user']['email'] ?? '' ) : '',
				$i === 0 ? preg_replace( "/\r\n|\n|\r/", ' ', $selection['message'] ?? '' ) : '',
				$i === 0 ? ( $selection['created_at'] ?? '' ) : '',
				$file['id'] ?? '',
				$file['name'] ?? '',
				$file['description'] ?? '',
				$file['reviewTag']['label'] ?? '',
				$file['webViewLink'] ?? '',
			] );
		}

		exit;
	}

	/* -------------------------------------------------------------------------
	 * DB
	 * ---------------------------------------------------------------------- */

	public function insert_selection( $shortcode_id, $selected, $user, $message, $selection = false ) {
		global $wpdb;

		$files = $this->normalize_files( $selected );
		$page  = esc_url_raw( $_REQUEST['page'] ?? '' );

		if ( ! empty( $selection['id'] ) ) {
			$wpdb->update(
				$this->table,
				[
					'files'      => maybe_serialize( $files ),
					'message'    => $message,
					'page'       => $page,
					'updated_at' => current_time( 'mysql' ),
				],
				[ 'id' => (int) $selection['id'] ],
				[ '%s', '%s', '%s', '%s' ],
				[ '%d' ]
			);

			return (int) $selection['id'];
		}

		$wpdb->insert(
			$this->table,
			[
				'shortcode_id' => (int) $shortcode_id,
				'user_id'      => (int) $user['id'],
				'email'        => sanitize_email( $user['email'] ),
				'files'        => maybe_serialize( $files ),
				'message'      => $message,
				'page'         => $page,
			],
			[ '%d', '%d', '%s', '%s', '%s', '%s' ]
		);

		return (int) $wpdb->insert_id;
	}

	public static function view() {
		echo '<div id="proof-selections-view" class="proof-selections-view"></div>';
	}

	/* -------------------------------------------------------------------------
	 * Singleton
	 * ---------------------------------------------------------------------- */

	public static function instance(): self {
		if ( null === self::$instance ) {
			self::$instance = new self();
		}

		return self::$instance;
	}
}