<?php

namespace GemBoards\hooks;

use GemBoards\Classes\Mention\Comment;
use GemBoards\Classes\Traits\Singleton;
use GemBoards\Entities\Notification;
use GemBoards\Entities\NotifiedUser;
use GemBoards\Utils\Helper;
use Throwable;
use WP_Comment;

if ( ! defined( 'ABSPATH' ) ) {
	exit;
} // if accessed directly, exit


class Activity {

	use Singleton;

	private function __construct() {
		// Card activity
		add_action( 'gemboards/card/created', [ $this, 'create_card_created_activity' ] );
		add_action( 'gemboards/card/title_updated', [ $this, 'create_card_title_activity' ] );
		add_action( 'gemboards/card/description_updated', [ $this, 'create_card_description_activity' ] );
		add_action( 'gemboards/card/column_id_updated', [ $this, 'create_card_move_column_activity' ], 10, 3 );
		add_action( 'gemboards/card/due_date_updated', [ $this, 'create_card_due_date_activity' ], 10, 3 );

		// card label and priority activity
		add_action( 'set_object_terms', [ $this, 'create_card_priority_activity' ], 10, 6 );
		add_action( 'added_term_relationship', [ $this, 'create_card_label_added_activity' ], 10, 3 );
		add_action( 'deleted_term_relationships', [ $this, 'create_card_label_removed_activity' ], 10, 3 );

		// Card user assignment activity
		add_action( 'gemboards/card/user_assigned', [ $this, 'add_card_users_activity' ], 10, 2 );
		add_action( 'gemboards/card/user_removed', [ $this, 'remove_card_users_activity' ], 10, 2 );

		// Card attachment activity
		add_action( 'gemboards/task/attachment/created', [ $this, 'create_card_attachment_added_activity' ], 10, 2 );
		add_action( 'gemboards/task/attachment/deleted', [ $this, 'create_card_attachment_deleted_activity' ], 10, 3 );

		// Card comment activity
		add_action( 'wp_insert_comment', [ $this, 'create_new_comment_notification' ], 10, 2 );
		add_action( 'wp_insert_comment', [ $this, 'create_mention_user_comment_notification' ], 10, 2 );
	}

	public function remove_actions() {
		// Card activity
		remove_action( 'gemboards/card/created', [ $this, 'create_card_created_activity' ] );
		remove_action( 'gemboards/card/title_updated', [ $this, 'create_card_title_activity' ] );
		remove_action( 'gemboards/card/description_updated', [ $this, 'create_card_description_activity' ] );
		remove_action( 'gemboards/card/column_id_updated', [ $this, 'create_card_move_column_activity' ] );
		remove_action( 'gemboards/card/due_date_updated', [ $this, 'create_card_due_date_activity' ] );

		// card label and priority activity
		remove_action( 'set_object_terms', [ $this, 'create_card_priority_activity' ] );
		remove_action( 'added_term_relationship', [ $this, 'create_card_label_added_activity' ] );
		remove_action( 'deleted_term_relationships', [ $this, 'create_card_label_removed_activity' ]);

		// Card user assignment activity
		remove_action( 'gemboards/card/user_assigned', [ $this, 'add_card_users_activity' ] );
		remove_action( 'gemboards/card/user_removed', [ $this, 'remove_card_users_activity' ] );

		// Card attachment activity
		remove_action( 'gemboards/task/attachment/created', [ $this, 'create_card_attachment_added_activity' ] );
		remove_action( 'gemboards/task/attachment/deleted', [ $this, 'create_card_attachment_deleted_activity' ]);
	}

	public function add_card_users_activity( int $card_id, int $user_id ) {
		try {
			$card = Helper::get_card( $card_id );
			if ( ! $card ) {
				return;
			}

			$current_user = wp_get_current_user();
			$user         = get_userdata( $user_id );

			if ( $user->ID !== $current_user->ID ) {
				$comment = sprintf(
					// translators: $1 is the username of assigned user and $2 is the username of assigned-by user.
					__( '@%1$s is assigned by @%2$s', 'gemboards' ),
					$user->user_login,
					$current_user->user_login ?? 'System'
				);
			} else {
				$comment = sprintf(
				// translators: $1 is the username of joined user.
					__( '@%1$s joined task.', 'gemboards' ),
					$user->user_login,
				);
			}

			$id = $this->insert_activity_comment( $card->get_task_id(), $comment );
			if ( ! $id || $user->ID === $current_user->ID ) {
				return;
			}

			$comment      = ( new Comment( $comment, $id, false ) )->rendered( true );
			$notification = new Notification();
			$notification->set_event_type( 'assigned_user_to_task' );
			$notification->set_notification_object_type( 'task' );
			$notification->set_object_id( $card->get_task_id() );
			$notification->set_from_user_id( get_current_user_id() );
			$notification->set_message( $comment );
			$notification->save();

			if ( Helper::get_notification_setting('assign_tasks') ) {
				$notified_user = new NotifiedUser();
				$notified_user->set_notification_id( $notification->get_id() );
				$notified_user->set_to_user_id( $user_id );
				$notified_user->save();
			}
			if ( Helper::get_notification_setting('assign_tasks', 'email') ) {
				do_action( 'gemboards/notification/send_email', $notification, $user_id );
			}
		} catch ( Throwable $e ) {
			Helper::error_log( $e->getMessage() );
		}
	}

	public function remove_card_users_activity( int $card_id, int $user_id ) {
		try {
			$card = Helper::get_card( $card_id );
			if ( ! $card ) {
				return;
			}

			$current_user = wp_get_current_user();
			$user         = get_userdata( $user_id );

			if ( $user->ID !== $current_user->ID ) {
				$comment = sprintf(
				// translators: $1 is the username of user.
					__( '@%1$s left task.', 'gemboards' ),
					$user->user_login,
				);
			} else {
				$comment = sprintf(
				// translators: $1 is the username of removed user and $2 is the username of removed-by user.
					__( '@%1$s is removed by @%2$s', 'gemboards' ),
					$user->user_login,
					$current_user->user_login ?? 'System'
				);
			}

			$id = $this->insert_activity_comment( $card->get_task_id(), $comment );
			if ( ! $id ) {
				return;
			}
			$comment = ( new Comment( $comment, $id, false ) )->rendered( true );

			$notification = new Notification();
			$notification->set_event_type( 'removed_user_from_task' );
			$notification->set_notification_object_type( 'task' );
			$notification->set_object_id( $card->get_task_id() );
			$notification->set_from_user_id( get_current_user_id() );
			$notification->set_message( $comment );
			$notification->save();

			if ( Helper::get_notification_setting('unassign_tasks') ) {
				$notified_user = new NotifiedUser();
				$notified_user->set_notification_id( $notification->get_id() );
				$notified_user->set_to_user_id( $user_id );
				$notified_user->save();
			}
			if ( Helper::get_notification_setting('unassign_tasks', 'email') ) {
				do_action( 'gemboards/notification/send_email', $notification, $user_id );
			}
		} catch ( Throwable $e ) {
			Helper::error_log( $e->getMessage() );
		}
	}

	public function create_card_created_activity( int $card_id ) {
		try {
			$card = Helper::get_card( $card_id );
			if ( ! $card ) {
				return;
			}

			$comment = sprintf(
			// translators: $1 is the username of card creation user and $2 is the card/task title.
				__( '@%1$s created task %2$s', 'gemboards' ),
				wp_get_current_user()->user_login,
				'<strong>' . $card->get_task()->post_title . '</strong>'
			);

			$this->insert_activity_comment( $card->get_task_id(), $comment );
		} catch ( Throwable $e ) {
			Helper::error_log( $e->getMessage() );
		}
	}

	public function create_card_title_activity( int $card_id ) {
		try {
			$card = Helper::get_card( $card_id );
			if ( ! $card ) {
				return;
			}

			$comment = sprintf(
			// translators: $1 is the username of card updated user.
				__( '@%1$s updated title.', 'gemboards' ),
				wp_get_current_user()->user_login,
			);

			$this->insert_activity_comment( $card->get_task_id(), $comment );
		} catch ( Throwable $e ) {
			Helper::error_log( $e->getMessage() );
		}
	}

	public function create_card_description_activity( int $card_id ) {
		$card = Helper::get_card( $card_id );
		if ( ! $card ) {
			return;
		}

		$comment = sprintf(
		// translators: $1 is the username of card updated user.
			__( '@%1$s updated description.', 'gemboards' ),
			wp_get_current_user()->user_login,
		);

		$comment_id = $this->insert_activity_comment( $card->get_task_id(), $comment );

		if ( ! Helper::get_notification_setting('mention_user') && ! Helper::get_notification_setting('mention_user', 'email') ) {
			return;
		}

		$task = $card->get_task();
		if ( ! $task ) {
			return;
		}

		$notification_content = sprintf(
		/* translators: 1: username of card-updated user, 2: Task title, 3: Board Title */
			__( '@%1$s mentioned you on %2$s card description of %3$s board.', 'gemboards' ),
			wp_get_current_user()->user_login,
			$task->post_title,
			$card->get_board()->get_title()
		);

		$notification    = new Notification();
		$notification->set_event_type( 'mention_user_description' );
		$notification->set_notification_object_type( 'task' );
		$notification->set_object_id( $card->get_task_id() );
		$notification->set_from_user_id( get_current_user_id() );
		$notification->set_message( $notification_content );
		$notification->set_meta( [
			'comment_id' => $comment_id,
		]);
		$notification->save();

		$usernames = $this->get_user_mentions($task->post_content);

		if ( Helper::get_notification_setting('mention_user') ) {
			foreach ( $usernames as $username ) {
				$user_id = username_exists( $username );
				if ( ! $user_id ) {
					continue;
				}

				$notified_user = new NotifiedUser();
				$notified_user->set_notification_id( $notification->get_id() );
				$notified_user->set_to_user_id( $user_id );
				$notified_user->save();
			}
		}

		if ( Helper::get_notification_setting('mention_user', 'email') ) {
			foreach ( $usernames as $username ) {
				$user_id = username_exists( $username );
				if ( ! $user_id ) {
					continue;
				}

				do_action( 'gemboards/notification/send_email', $notification, $user_id );
			}
		}

	}

	public function create_card_move_column_activity( int $card_id, $new_value, $old_value ) {
		$card = Helper::get_card( $card_id );
		if ( ! $card ) {
			return;
		}

		$new_column = Helper::get_column( $new_value );
		if ( ! $new_column ) {
			return;
		}
		$old_column = Helper::get_column( $old_value );
		if ( ! $old_column ) {
			return;
		}
		if ( $new_column->get_id() === $old_column->get_id() ) {
			return;
		}

		$comment = sprintf(
		// translators: $1 is the username of card updated user, $2 is the recent stage, $3 is the current stage.
			__( '@%1$s changed stage from %2$s to %3$s', 'gemboards' ),
			wp_get_current_user()->user_login,
			'<del><strong>' . $old_column->get_title() . '</strong></del>',
			'<strong>' . $new_column->get_title() . '</strong>'
		);

		$comment_id = $this->insert_activity_comment( $card->get_task_id(), $comment );

		if ( ! Helper::get_notification_setting('stage_changes') && ! Helper::get_notification_setting('stage_changes', 'email') ) {
			return;
		}

		$comment_content = sprintf(
		// translators: $1 is the new stage, and $2 is the username of card updated user.
			__( 'Task moved to %1$s stage by @%2$s', 'gemboards' ),
			'<strong>' . $new_column->get_title() . '</strong>',
			wp_get_current_user()->user_login
		);
		$comment_content = ( new Comment( $comment_content, $comment_id, false ) )->rendered( true );
		$notification    = new Notification();
		$notification->set_event_type( 'stage_changed' );
		$notification->set_notification_object_type( 'task' );
		$notification->set_object_id( $card->get_task_id() );
		$notification->set_from_user_id( get_current_user_id() );
		$notification->set_message( $comment_content );
		$notification->set_meta( [
			'old_column_id' => $old_column->get_id(),
			'new_column_id' => $new_column->get_id(),
		] );
		$notification->save();

		if ( Helper::get_notification_setting('stage_changes') && ! empty($card->get_assignees()) ) {
			foreach ( $card->get_assignees() as $assignee ) {
				if ( $assignee->get_user_id() === get_current_user_id() ) {
					continue;
				}
				$notified_user = new NotifiedUser();
				$notified_user->set_notification_id( $notification->get_id() );
				$notified_user->set_to_user_id( $assignee->get_user_id() );
				$notified_user->save();
			}
		}

		if ( Helper::get_notification_setting('stage_changes', 'email') ) {
			foreach ( $card->get_assignees() as $assignee ) {
				if ( $assignee->get_user_id() === get_current_user_id() ) {
					continue;
				}
				do_action( 'gemboards/notification/send_email', $notification, $assignee->get_user_id() );
			}
		}
	}

	public function create_card_due_date_activity( int $card_id, $new_value, $old_value ) {
		$card = Helper::get_card( $card_id );
		if ( ! $card || ( ! empty( $new_value ) && ! empty( $old_value ) && $new_value->format( 'Y-m-d' ) === $old_value->format( 'Y-m-d' ) ) || ( empty( $new_value ) && empty( $old_value ) ) ) {
			return;
		}

		if ( empty( $new_value ) ) {
			$comment = sprintf(
			// translators: $1 is the username of card updated user.
				__( '@%1$s removed Due Date.', 'gemboards' ),
				wp_get_current_user()->user_login,
			);
		} else {
			$comment = sprintf(
			// translators: $1 is the username of card updated user and $2 is the due-date.
				__( '@%1$s added Due Date %2$s', 'gemboards' ),
				wp_get_current_user()->user_login,
				'<strong>' . $new_value->format( 'Y-m-d' ) . '</strong>',
			);
		}

		$this->insert_activity_comment( $card->get_task_id(), $comment );
	}

	public function create_card_priority_activity( $object_id, $terms, $tt_ids, $taxonomy, $append, $old_tt_ids ) {
		if ( 'gemboards_priority' !== $taxonomy ) {
			return;
		}

		$old_tt_id = reset( $old_tt_ids );
		if ( ! $old_tt_id ) {
			return;
		}
		$old_term = get_term_by( 'term_taxonomy_id', $old_tt_id, $taxonomy );
		if ( ! $old_term ) {
			return;
		}

		$new_tt_id = reset( $tt_ids );
		if ( ! $new_tt_id ) {
			return;
		}
		$new_term = get_term_by( 'term_taxonomy_id', $new_tt_id, $taxonomy );
		if ( ! $new_term ) {
			return;
		}

		if ( $old_term->term_id === $new_term->term_id ) {
			return;
		}

		$comment = sprintf(
		// translators: $1 is the username of card updated user, $2 is the old priority and $3 is the new priority.
			__( '@%1$s changed priority from %2$s to %3$s', 'gemboards' ),
			wp_get_current_user()->user_login,
			'<del><strong>' . $old_term->name . '</strong></del>',
			'<strong>' . $new_term->name . '</strong>'
		);

		$this->insert_activity_comment( $object_id, $comment );
	}

	public function create_card_label_added_activity( $object_id, $tt_id, $taxonomy ) {
		if ( 'gemboards_label' !== $taxonomy ) {
			return;
		}

		$term = get_term_by( 'term_taxonomy_id', $tt_id, $taxonomy );
		if ( ! $term ) {
			return;
		}

		$comment = sprintf(
		// translators: $1 is the username of card updated user and $2 is the newly added label.
			__( '@%1$s added label %2$s', 'gemboards' ),
			wp_get_current_user()->user_login,
			'<strong>' . $term->name . '</strong>',
		);

		$this->insert_activity_comment( $object_id, $comment );
	}

	public function create_card_label_removed_activity( $object_id, $tt_ids, $taxonomy ) {
		if ( 'gemboards_label' !== $taxonomy ) {
			return;
		}

		$tt_id = reset( $tt_ids );
		if ( ! $tt_id ) {
			return;
		}
		$term = get_term_by( 'term_taxonomy_id', $tt_id, $taxonomy );
		if ( ! $term ) {
			return;
		}

		$comment = sprintf(
		// translators: $1 is the username of card updated user and $2 is the removed label.
			__( '@%1$s removed label %2$s', 'gemboards' ),
			wp_get_current_user()->user_login,
			'<strong>' . $term->name . '</strong>',
		);

		$this->insert_activity_comment( $object_id, $comment );
	}

	public function create_card_attachment_added_activity( int $id, int $task_id ) {
		$task_attachment = Helper::get_task_attachment( $id );
		if ( ! $task_attachment ) {
			return;
		}

		$comment = sprintf(
		// translators: $1 is the username of card updated user and $2 is the link-html of newly added attachment.
			__( '@%1$s added attachment %2$s', 'gemboards' ),
			wp_get_current_user()->user_login,
			'<a href="' . esc_attr( $task_attachment->get_file_url() ) . '" target="_blank">' . esc_html( $task_attachment->get_file_name() ?? $task_attachment->get_file_url() ) . '</a>'
		);

		$this->insert_activity_comment( $task_id, $comment );
	}

	public function create_card_attachment_deleted_activity( int $id, int $task_id, array $data ) {
		$comment = sprintf(
		// translators: $1 is the username of card updated user and $2 is the link-html of removed attachment.
			__( '@%1$s removed attachment %2$s', 'gemboards' ),
			wp_get_current_user()->user_login,
			'<a href="' . esc_attr( $data['file_url'] ) . '" target="_blank">' . esc_html( $data['file_name'] ?? $data['file_url'] ) . '</a>'
		);

		$this->insert_activity_comment( $task_id, $comment );
	}

	public function create_new_comment_notification( int $comment_id, WP_Comment $comment ) {
		if ( 'task_comment' !== $comment->comment_type || 'gemboards_task' !== get_post_type( $comment->comment_post_ID ) || ( ! Helper::get_notification_setting('new_comment') && ! Helper::get_notification_setting('new_comment', 'email') ) ) {
			return;
		}

		$task_id        = $comment->comment_post_ID;
		$card           = Helper::get_card_by_task_id($task_id);
		$comment_author = get_user($comment->user_id);
		if ( ! $comment_author ) {
			return;
		}
		$comment_content = sprintf(
		// translators: $1 is the username of the comment author.
			__( '@%1$s commented on task.', 'gemboards'),
			$comment_author->user_login
		);
		$comment_content = ( new Comment( $comment_content, $comment_id, false ) )->rendered( true );
		$notification    = new Notification();
		$notification->set_event_type( 'new_comment' );
		$notification->set_notification_object_type( 'task' );
		$notification->set_object_id( $task_id );
		$notification->set_from_user_id( get_current_user_id() );
		$notification->set_message( $comment_content );
		$notification->set_meta( [
			'comment_id' => $comment_id,
		]);
		$notification->save();

		if ( Helper::get_notification_setting('new_comment') ) {
			if ( ! empty( $card->get_assignees()) ) {
				foreach ( $card->get_assignees() as $assignee ) {
					if ( $assignee->get_user_id() === absint($comment->user_id) ) {
						continue;
					}
					$notified_user = new NotifiedUser();
					$notified_user->set_notification_id( $notification->get_id() );
					$notified_user->set_to_user_id( $assignee->get_user_id() );
					$notified_user->save();
				}
			}
		}

		if ( Helper::get_notification_setting('new_comment', 'email') ) {
			if ( $card && ! empty( $card->get_assignees()) ) {
				foreach ( $card->get_assignees() as $assignee ) {
					if ( $assignee->get_user_id() === absint($comment->user_id) ) {
						continue;
					}
					do_action( 'gemboards/notification/send_email', $notification, $assignee->get_user_id() );
				}
			}
		}
	}

	public function create_mention_user_comment_notification( int $comment_id, WP_Comment $comment ) {
		if ( 'task_comment' !== $comment->comment_type || 'gemboards_task' !== get_post_type( $comment->comment_post_ID ) || ( ! Helper::get_notification_setting('mention_user') && ! Helper::get_notification_setting('mention_user', 'email') ) ) {
			return;
		}

		$task_id        = $comment->comment_post_ID;
		$card           = Helper::get_card_by_task_id($task_id);
		$comment_author = get_user($comment->user_id);
		if ( ! $comment_author ) {
			return;
		}

		$task = $card->get_task();
		if ( ! $task ) {
			return;
		}

		$notification_content = sprintf(
		/* translators: 1: username of card-updated user, 2: Task title, 3: Board Title */
			__( '@%1$s mentioned you on %2$s card\'s comment of %3$s board.', 'gemboards' ),
			wp_get_current_user()->user_login,
			$task->post_title,
			$card->get_board()->get_title()
		);

		$notification    = new Notification();
		$notification->set_event_type( 'mention_user_comment' );
		$notification->set_notification_object_type( 'task' );
		$notification->set_object_id( $card->get_task_id() );
		$notification->set_from_user_id( get_current_user_id() );
		$notification->set_message( $notification_content );
		$notification->set_meta( [
			'comment_id' => $comment_id,
		]);
		$notification->save();

		$usernames = $this->get_user_mentions($comment->comment_content);

		if ( Helper::get_notification_setting('mention_user') ) {
			foreach ( $usernames as $username ) {
				$user_id = username_exists( $username );
				if ( ! $user_id ) {
					continue;
				}

				$notified_user = new NotifiedUser();
				$notified_user->set_notification_id( $notification->get_id() );
				$notified_user->set_to_user_id( $user_id );
				$notified_user->save();
			}
		}

		if ( Helper::get_notification_setting('mention_user', 'email') ) {
			foreach ( $usernames as $username ) {
				$user_id = username_exists( $username );
				if ( ! $user_id ) {
					continue;
				}

				do_action( 'gemboards/notification/send_email', $notification, $user_id );
			}
		}
	}

	private function insert_activity_comment( int $task_id, string $comment ) {
		return wp_insert_comment( [
			'comment_post_ID'  => $task_id,
			'comment_author'   => wp_get_current_user()->user_login ?? 'System',
			'comment_content'  => $comment,
			'comment_type'     => 'activity',
			'comment_approved' => 1,
			'user_id'          => get_current_user_id(),
		] );
	}

	/**
	 * Array of usernames without the @ symbol.
	 *
	 * @param string $content
	 *
	 * @return array
	 */
	private function get_user_mentions( string $content ): array {
		preg_match_all( '/@([a-zA-Z0-9_]+)/', $content, $matches );

		return $matches[1];
	}


}
