<?php

namespace GemBoards\Ajax;

use GemBoards\Classes\AbstractAjaxHandler;
use GemBoards\Classes\EventStreamServer;
use GemBoards\Classes\Exception\GemboardsException;
use GemBoards\Classes\Exception\GemboardsInvalidArgumentException;
use GemBoards\Collections\CardAssigneeCollection;
use GemBoards\Collections\CardCollection;
use GemBoards\Collections\TaskAttachmentCollection;
use GemBoards\Entities\Card;
use GemBoards\entities\CardAssignee;
use GemBoards\Entities\Column;
use GemBoards\Entities\FavouriteBoard;
use GemBoards\Entities\TaskAttachment;
use GemBoards\hooks\Activity;
use GemBoards\Utils\Helper;
use GemBoardsPro\Collections\SprintCollection;
use GemBoardsPro\Collections\TaskChecklistCollection;
use GemBoardsPro\Collections\TaskChecklistGroupCollection;
use GemBoardsPro\Entities\Sprint;
use GemBoardsPro\Entities\TaskChecklistGroup;

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

class Board extends AbstractAjaxHandler {

	public function __construct() {
		$this->actions = [
			'create_board'                    => [
				'callback'   => [ $this, 'create_board' ],
				'permission' => 'update_projects',
				'fields'     => [
					'board_title'      => 'string',
					'board_type'       => 'string',
					'owner_id'         => 'integer',
					'project_id'       => 'integer',
					'folder_id'        => 'integer',
					'board_icon_color' => 'string',
					'is_private'       => 'boolean',
				],
			],
			'update_board'                    => [
				'callback' => [ $this, 'update_board' ],
				'fields'   => [
					'id'                  => 'integer',
					'board_title'         => 'string',
					'board_type'          => 'string',
					'owner_id'            => 'integer',
					'project_id'          => 'integer',
					'folder_id'           => 'integer',
					'completed_column_id' => 'integer',
					'board_icon_color'    => 'string',
					'is_private'          => 'boolean',
				],
			],
			'get_board'                       => [
				'callback' => [ $this, 'get_board' ],
				'fields'   => [
					'id' => 'integer',
				],
			],
			'archive_board'                   => [
				'callback' => [ $this, 'archive_board' ],
				'fields'   => [
					'id' => 'integer',
				],
			],
			'restore_board'                   => [
				'callback' => [ $this, 'restore_board' ],
				'fields'   => [
					'id' => 'integer',
				],
			],
			'delete_board'                    => [
				'callback' => [ $this, 'delete_board' ],
				'fields'   => [
					'id' => 'integer',
				],
			],
			'add_board_to_favourite'          => [
				'callback'   => [ $this, 'add_board_to_favourite' ],
				'permission' => 'view_projects',
				'fields'     => [
					'board_id'   => 'integer',
					'sort_order' => 'integer',
				],
			],
			'update_favourite_boards_sorting' => [
				'callback' => [ $this, 'update_favourite_boards_sorting' ],
				'fields'   => [
					'favourites' => [
						[
							'favourite_id' => 'integer',
							'sort_order'   => 'integer',
						],
					],
				],
			],
			'remove_board_from_favourite'     => [
				'callback' => [ $this, 'remove_board_from_favourite' ],
				'fields'   => [
					'favourite_id' => 'integer',
				],
			],
			'duplicate_board'                 => [
				'callback' => [ $this, 'duplicate_board' ],
				'fields'   => [
					'id'    => 'integer',
					'title' => 'string',
				],
			],
			'duplicate_cards'                 => [
				'callback' => [ $this, 'duplicate_cards' ],
				'fields'   => [
					'from_id'      => [
						'label'    => __( 'From Board ID', 'gemboards' ),
						'rules'    => 'absint|min:1|required',
						'messages' => [
							'required' => '%s cannot be empty.',
							'min'      => '%s cannot be zero.',
						],
					],
					'to_id'        => [
						'label'    => __( 'New Board ID', 'gemboards' ),
						'rules'    => 'absint|min:1|required',
						'messages' => [
							'required' => '%s cannot be empty.',
							'min'      => '%s cannot be zero.',
						],
					],
					'current_page' => [
						'label'    => __( 'Current page', 'gemboards' ),
						'rules'    => 'absint|min:1',
						'default'  => 1,
						'messages' => [
							'required' => '%s cannot be empty.',
							'min'      => '%s cannot be zero.',
						],
					],
				],
			],
			'get_board_columns'               => [
				'callback'   => [ $this, 'get_board_columns' ],
				'permission' => 'view_projects',
				'fields'     => [
					'board_id' => 'integer',
				],
			],
		];
	}

	public function create_board( array $payload ) {
		if ( empty( $payload['board_title'] ) ) {
			wp_send_json_error( [
				'message' => __( 'Board title is required', 'gemboards' ),
			] );
		}

		if ( empty( $payload['project_id'] ) ) {
			wp_send_json_error( [
				'message' => __( 'Project id is required', 'gemboards' ),
			] );
		}

		$title      = $payload['board_title'];
		$board_type = $payload['board_type'] ?? 'kanban';
		$owner_id   = $payload['owner_id'] ?? get_current_user_id();

		$project_id = $payload['project_id'];
		$project    = Helper::get_project( $project_id );
		if ( ! $project ) {
			wp_send_json_error( [
				'message' => __( 'Project not found', 'gemboards' ),
			] );
		}

		$folder_id = $payload['folder_id'] ?? null;
		if ( $folder_id ) {
			$folder = Helper::get_folder( $folder_id );
			if ( ! $folder ) {
				wp_send_json_error( [
					'message' => __( 'Folder not found', 'gemboards' ),
				] );
			}
		}

		$icon_color = $payload['board_icon_color'] ?? '';
		$is_private = $payload['is_private'] ?? false;

		$board = new \GemBoards\Entities\Board();
		$board->set_title( $title );
		$board->set_board_type( $board_type );
		$board->set_owner_id( $owner_id );
		$board->set_project_id( $project_id );
		$board->set_folder_id( $folder_id );
		$board->set_icon_color( $icon_color );
		$board->set_is_private( $is_private );
		$result = $board->save();
		if ( is_wp_error( $result ) ) {
			wp_send_json_error( [
				'message' => $result->get_error_message(),
			] );
		}

		$columns = [
			[
				'title'      => 'To Do',
				'color'      => '#141A24',
				'sort_order' => 1,
			],
			[
				'title'      => 'In Progress',
				'color'      => '#EA580C',
				'sort_order' => 2,
			],
			[
				'title'      => 'Done',
				'color'      => '#22A06B',
				'sort_order' => 3,
			],
		];
		foreach ( $columns as $column_data ) {
			$column = new Column();
			$column->set_board_id( $board->get_id() );
			$column->set_title( $column_data['title'] );
			$column->set_slug( sanitize_title( $column_data['title'] ) );
			$column->set_color( $column_data['color'] );
			$column->set_sort_order( $column_data['sort_order'] );
			$column->save();
		}

		$done_column_id = 0;
		foreach ( $board->get_columns() as $column ) {
			if ( 'done' === $column->get_slug() ) {
				$done_column_id = $column->get_id();
				break;
			}
		}

		if ( $done_column_id ) {
			$board->set_completed_column_id( $done_column_id );
			$board->save();
		}

		wp_send_json_success( $this->get_board_array( $board ) );
	}

	public function update_board( array $payload ) {
		if ( empty( $payload['id'] ) ) {
			wp_send_json_error( [
				'message' => __( 'Board ID is required.', 'gemboards' ),
			] );
		}

		if ( empty( $payload['board_title'] ) ) {
			wp_send_json_error( [
				'message' => __( 'Board Title is required.', 'gemboards' ),
			] );
		}

		if ( ! current_user_can( 'update_projects', [
			'board_id' => $payload['id'],
		] ) ) {
			wp_send_json_error( [ 'message' => __( 'You do not have permission to update this board.', 'gemboards' ) ] );
		}

		$id             = $payload['id'];
		$title          = $payload['board_title'];
		$board_type     = $payload['board_type'] ?? null;
		$owner_id       = $payload['owner_id'] ?? 0;
		$project_id     = $payload['project_id'] ?? 0;
		$folder_id      = $payload['folder_id'] ?? null;
		$icon_color     = $payload['board_icon_color'] ?? '';
		$is_private     = $payload['is_private'] ?? false;
		$done_column_id = ! empty( $payload['completed_column_id'] ) ? absint( $payload['completed_column_id'] ) : 0;

		if ( $project_id ) {
			$project = Helper::get_project( $project_id );
			if ( ! $project ) {
				wp_send_json_error( [
					'message' => __( 'Invalid project.', 'gemboards' ),
				] );
			}
		}

		if ( $done_column_id ) {
			$column = Helper::get_column( $done_column_id );
			if ( ! $column ) {
				wp_send_json_error( [
					'message' => __( 'Column does not exist.', 'gemboards' ),
				] );
			}
		}

		if ( $folder_id ) {
			$folder = Helper::get_folder( $folder_id );
			if ( ! $folder ) {
				wp_send_json_error( [
					'message' => __( 'Invalid folder.', 'gemboards' ),
				] );
			}
		}

		$board = Helper::get_board( $id );
		if ( ! $board ) {
			wp_send_json_error( [
				'message' => __( 'Invalid board id', 'gemboards' ),
			] );
		}

		$board->set_title( $title );

		if ( $board_type ) {
			$board->set_board_type( $board_type );
		}

		if ( $owner_id ) {
			$board->set_owner_id( $owner_id );
		}

		if ( $project_id ) {
			$board->set_project_id( $project_id );
		}

		if ( $folder_id ) {
			$board->set_folder_id( $folder_id );
		}

		if ( ! empty( $icon_color ) ) {
			$board->set_icon_color( $icon_color );
		}

		if ( $is_private ) {
			$board->set_is_private( $is_private );
		}

		if ( $done_column_id ) {
			$board->set_completed_column_id( $done_column_id );
		}

		$result = $board->save();
		if ( is_wp_error( $result ) ) {
			wp_send_json_error( [
				'message' => $result->get_error_message(),
			] );
		}

		if ( $board->get_completed_column_id() ) {
			global $wpdb;
			// phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- Clearing cach via entity class's `clear_cache` method.
			$wpdb->query(
				$wpdb->prepare(
					"UPDATE {$wpdb->prefix}gemboards_cards
					SET
						is_completed = 1
					WHERE
						column_id = %d
						AND is_completed = 1 AND archived = 0", $board->get_completed_column_id()
				)
			); // phpcs:enable
			( new Card() )->clear_cache();
		}

		wp_send_json_success( $this->get_board_array( $board ) );
	}

	public function get_board( $request ) {
		$id = $request['id'] ?? 0;

		if ( empty( $id ) ) {
			wp_send_json_error( [
				'message' => __( 'Board ID is required.', 'gemboards' ),
			] );
		}

		if ( ! current_user_can( 'view_projects', [
			'board_id' => $id,
		] ) ) {
			wp_send_json_error( [ 'message' => __( 'You do not have permission to view this board.', 'gemboards' ) ] );
		}

		$board = Helper::get_board( $id );
		if ( ! $board ) {
			wp_send_json_error( [
				'message' => __( 'Invalid board id', 'gemboards' ),
			] );
		}

		wp_send_json_success( $this->get_board_array( $board ) );
	}

	public function archive_board( array $payload ) {
		$id = $payload['id'] ?? 0;

		if ( empty( $id ) ) {
			wp_send_json_error( [
				'message' => __('Board ID is required.', 'gemboards'),
			] );
		}

		if ( ! current_user_can( 'update_projects', [
			'board_id' => $id,
		] ) ) {
			wp_send_json_error( [ 'message' => __( 'You do not have permission to archive this board.', 'gemboards' ) ] );
		}

		$board = Helper::get_board( $id );
		if ( ! $board ) {
			wp_send_json_error( [
				'message' => __( 'Invalid board id', 'gemboards' ),
			] );
		}

		$board->set_board_status( 'archived' );
		$result = $board->save();
		if ( is_wp_error( $result ) ) {
			wp_send_json_error( [
				'message' => $result->get_error_message(),
			] );
		}

		wp_send_json_success( [ 'message' => __( 'Board archived successfully.', 'gemboards' ) ] );
	}

	public function restore_board( array $payload ) {
		$id = $payload['id'] ?? 0;

		if ( empty( $id ) ) {
			wp_send_json_error( [
				'message' => __('Board ID is required.', 'gemboards'),
			] );
		}

		if ( ! current_user_can( 'update_projects', [
			'board_id' => $id,
		] ) ) {
			wp_send_json_error( [ 'message' => __( 'You do not have permission to restore this board.', 'gemboards' ) ] );
		}

		$board = Helper::get_board( $id );
		if ( ! $board ) {
			wp_send_json_error( [
				'message' => __( 'Invalid board id', 'gemboards' ),
			] );
		}

		$board->set_board_status( 'active' );
		$result = $board->save();
		if ( is_wp_error( $result ) ) {
			wp_send_json_error( [
				'message' => $result->get_error_message(),
			] );
		}

		wp_send_json_success( [ 'message' => __( 'Board restored successfully.', 'gemboards' ) ] );
	}

	public function delete_board( $request ) {
		$id = $request['id'] ?? 0;

		if ( empty( $id ) ) {
			wp_send_json_error( [
				'message' => 'Board ID is required.',
			] );
		}

		if ( ! current_user_can( 'update_projects', [
			'board_id' => $id,
		] ) ) {
			wp_send_json_error( [ 'message' => __( 'You do not have permission to delete this board.', 'gemboards' ) ] );
		}

		$board = Helper::get_board( $id );
		if ( ! $board ) {
			wp_send_json_error( [
				'message' => __( 'Invalid board id', 'gemboards' ),
			] );
		}
		try {
			$board->delete();
			wp_send_json_success( [ 'message' => 'Board deleted successfully.' ] );
		} catch ( GemboardsException $e ) {
			wp_send_json_error( [ 'message' => $e->get_wp_error()->get_error_message() ] );
		}
	}

	public function add_board_to_favourite( array $payload ) {
		if ( empty( $payload['board_id'] ) ) {
			wp_send_json_error( [
				'message' => __( 'Board ID is required.', 'gemboards' ),
			] );
		}
		$board_id = $payload['board_id'];
		$board    = Helper::get_board( $board_id );
		if ( ! $board ) {
			wp_send_json_error( [
				'message' => __( 'Invalid board id', 'gemboards' ),
			] );
		}
		$sort_order = $payload['sort_order'] ?? 1;

		$favourite_board = new FavouriteBoard();
		$favourite_board->set_board_id( $board_id );
		$favourite_board->set_user_id( get_current_user_id() );
		$favourite_board->set_sort_order( $sort_order );
		$favourite_board->save();

		wp_send_json_success( [
			'favourite_id' => $favourite_board->get_id(),
		] );
	}

	public function update_favourite_boards_sorting( array $payload ) {
		$favourites = $payload['favourites'] ?? [];
		if ( empty( $favourites ) ) {
			wp_send_json_error( [
				'message' => __( 'Favourite items are required.', 'gemboards' ),
			] );
		}

		$favourite_objects = [];
		foreach ( $favourites as $favourite ) {
			if ( empty( $favourite['favourite_id'] ) ) {
				wp_send_json_error( [
					'message' => __( 'Favourite ID is required.', 'gemboards' ),
				] );
			}

			if ( empty( $favourite['sort_order'] ) ) {
				wp_send_json_error( [
					'message' => __( 'Sort order is required.', 'gemboards' ),
				] );
			}

			$favourite_obj = Helper::get_favourite_board( $favourite['favourite_id'] );
			if ( ! $favourite_obj ) {
				wp_send_json_error( [
					'message' => __( 'Invalid favourite id', 'gemboards' ),
				] );
			}

			if ( ! $favourite_obj->get_user_id() || $favourite_obj->get_user_id() !== get_current_user_id() ) {
				wp_send_json_error([
					'message' => __('Invalid favourite id', 'gemboards'),
				]);
			}

			$favourite_obj->set_sort_order($favourite['sort_order']);
			$favourite_objects[] = $favourite_obj;
		}

		foreach ( $favourite_objects as $favourite ) {
			$favourite->save();
		}

		wp_send_json_success();
	}

	public function remove_board_from_favourite( array $payload ) {
		if ( empty( $payload['favourite_id'] ) ) {
			wp_send_json_error( [
				'message' => __( 'Favourite ID is required.', 'gemboards' ),
			] );
		}

		$favourite_id    = $payload['favourite_id'];
		$favourite_board = Helper::get_favourite_board( $favourite_id );
		if ( ! $favourite_board ) {
			wp_send_json_error( [
				'message' => __( 'Invalid favourite id', 'gemboards' ),
			] );
		}
		if ( ! $favourite_board->get_user_id() || $favourite_board->get_user_id() !== get_current_user_id() ) {
			wp_send_json_error([
				'message' => __('Invalid favourite id', 'gemboards'),
			]);
		}

		try {
			$favourite_board->delete();
			wp_send_json_success();
		} catch ( GemboardsException $e ) {
			Helper::error_log( $e->getMessage() );
			wp_send_json_error( [
				'message' => __( 'Error removing favourite board', 'gemboards' ),
			] );
		}
	}

	public function duplicate_board( array $payload ) {
		$board_id = $payload['id'] ?? 0;
		if ( ! $board_id ) {
			wp_send_json_error( [
				'message' => __( 'Board ID is required.', 'gemboards' ),
			] );
		}

		if ( ! current_user_can( 'update_projects', [
			'board_id' => $board_id,
		] ) ) {
			wp_send_json_error( [ 'message' => __( 'You do not have permission to duplicate this board.', 'gemboards' ) ] );
		}

		if ( empty( $payload['title'] ) ) {
			wp_send_json_error( [
				'message' => __( 'Board title is required.', 'gemboards' ),
			] );
		}
		$title = $payload['title'];

		$board = Helper::get_board( $board_id );
		if ( ! $board ) {
			wp_send_json_error( [
				'message' => __( 'Invalid Board ID.', 'gemboards' ),
			] );
		}
		$columns             = $board->get_columns();
		$completed_column_id = $board->get_completed_column_id();

		$board->set_id( 0 );
		$board->set_title( $title );
		$result = $board->save();
		if ( is_wp_error( $result ) ) {
			wp_send_json_error( [
				'message' => $result->get_error_message(),
			] );
		}

		$columns_mapping = [];
		foreach ( $columns as $column ) {
			$previous_column_id = $column->get_id();
			$column->set_id( 0 );
			$column->set_board_id( $board->get_id() );
			$column->save();
			if ( $previous_column_id === $completed_column_id ) {
				$board->set_completed_column_id( $column->get_id() );
			}
			$columns_mapping[ $previous_column_id ] = $column->get_id();
		}
		set_transient( 'gemboards_columns_mapping_' . $board->get_id(), $columns_mapping, DAY_IN_SECONDS );

		try {
			$cards_count = ( new CardCollection( [
				'fields' => 'count',
				'where'  => [
					[
						'key'   => 'board_id',
						'value' => $board_id,
					],
					[
						'key'   => 'archived',
						'value' => 0,
					],
				],
			] ) )->get_results();
			$cards_count = reset( $cards_count );
		} catch ( GemboardsInvalidArgumentException $e ) {
			Helper::error_log( $e->getMessage() );
			$cards_count = 0;
		}
		$total_pages = ceil( $cards_count / 5 );

		if ( 'scrum' === $board->get_board_type() ) {
			$sprints_mapping = [];
			try {
				/** @var Sprint[] $sprints */
				$sprints = ( new SprintCollection( [
					'per_page' => - 1,
					'where'    => [
						[
							'key'   => 'board_id',
							'value' => $board_id,
						],
						[
							'key'   => 'is_completed',
							'value' => 0,
						],
					],
				] ) )->get_results();
				foreach ( $sprints as $sprint ) {
					$old_sprint_id = $sprint->get_id();
					$sprint->set_id( 0 );
					$sprint->set_board_id( $board->get_id() );
					$sprint->save();
					$sprints_mapping[ $old_sprint_id ] = $sprint->get_id();
				}
			} catch ( GemboardsInvalidArgumentException $e ) {
				Helper::error_log( $e->getMessage() );
			}
			set_transient( 'gemboards_sprints_mapping_' . $board->get_id(), $sprints_mapping, DAY_IN_SECONDS );
		}

		wp_send_json_success( array_merge( $this->get_board_array( $board ), [
			'cards_count' => $cards_count,
			'total_pages' => $total_pages,
		] ) );
	}

	public function duplicate_cards( array $payload ) {
		$from_id = $payload['from_id'];
		$to_id   = $payload['to_id'];

		if ( ! current_user_can( 'update_projects', [
			'board_id' => $from_id,
		] ) || ! current_user_can( 'update_projects', [
			'board_id' => $to_id,
		] ) ) {
			wp_send_json_error( [ 'message' => __( 'You do not have permission to duplicate cards.', 'gemboards' ) ] );
		}

		$old_board = Helper::get_board( $from_id );
		if ( ! $old_board ) {
			wp_send_json_error( [
				'message' => __( 'Invalid From Board id', 'gemboards' ),
			] );
		}

		$new_board = Helper::get_board( $to_id );
		if ( ! $new_board ) {
			wp_send_json_error( [
				'message' => __( 'Invalid To Board id', 'gemboards' ),
			] );
		}

		$current_page    = $payload['current_page'];
		$columns_mapping = get_transient('gemboards_columns_mapping_' . $new_board->get_id()) ?? [];

		$sprints_mapping = [];
		if ( 'scrum' === $new_board->get_board_type() ) {
			$sprints_mapping = get_transient( 'gemboards_sprints_mapping_' . $new_board->get_id() ) ?? [];
		}

		$sse = new EventStreamServer();
		$sse->listen( function () use ( $sse, $current_page, $new_board, $old_board, $columns_mapping, $sprints_mapping ) {
			/** @var Card[] $cards */
			$cards = ( new CardCollection( [
				'per_page' => 5,
				'page'     => $current_page,
				'where'    => [
					[
						'key'   => 'board_id',
						'value' => $old_board->get_id(),
					],
					[
						'key'   => 'archived',
						'value' => 0,
					],
				],
			] ) )->get_results();

			Activity::init()->remove_actions();
			foreach ( $cards as $card ) {
				$old_card_id = $card->get_id();
				$card->set_board_id( $new_board->get_id() );
				$card->set_sprint_id( $sprints_mapping[ $card->get_sprint_id() ] ?? 0 );
				$card->set_column_id( $columns_mapping[ $card->get_column_id() ] ?? 0 );

				$old_task    = $card->get_task();
				$old_task_id = $old_task->ID;
				$task_id     = wp_insert_post( [
					'post_title'   => $old_task->post_title,
					'post_content' => $old_task->post_content,
					'post_type'    => Helper::BOARD_TASK_POST_TYPE,
					'post_status'  => 'publish',
					'post_author'  => $old_task->post_author,
				] );
				if ( is_wp_error( $task_id ) ) {
					$sse->emitEvent( [
						'type'    => 'error',
						'message' => $task_id->get_error_message(),
					] );
				}
				$card->set_task_id( $task_id );
				$card->set_id( 0 );
				$card->save();

				$priorities = wp_get_object_terms( $old_task_id, 'gemboards_priority');
				wp_set_object_terms( $task_id, array_map(fn( $priority) => $priority->term_id, $priorities), 'gemboards_priority' );

				$labels = wp_get_object_terms( $old_task_id, 'gemboards_label');
				wp_set_object_terms( $task_id, array_map(fn( $label) => $label->term_id, $labels), 'gemboards_label' );

				/** @var CardAssignee[] $card_assignees */
				$card_assignees = ( new CardAssigneeCollection([
					'per_page' => -1,
					'where'    => [
						[
							'key'   => 'card_id',
							'value' => $old_card_id,
						],
					],
				]) )->get_results();
				foreach ( $card_assignees as $card_assignee ) {
					$card_assignee->set_card_id( $card->get_id() );
					$card_assignee->set_id( 0 );
					$card_assignee->save();
				}

				$old_comments = get_comments( [
					'post_id' => $old_task_id,
					'status'  => 'all',
					'orderby' => 'comment_date_gmt',
					'order'   => 'ASC',
				]);
				foreach ( $old_comments as $old_comment ) {
					$new_comment_id = wp_insert_comment( [
						'comment_post_ID'      => $task_id,
						'comment_author'       => $old_comment->comment_author,
						'comment_author_email' => $old_comment->comment_author_email,
						'comment_author_url'   => $old_comment->comment_author_url,
						'comment_author_IP'    => $old_comment->comment_author_IP,
						'comment_date'         => $old_comment->comment_date,
						'comment_date_gmt'     => $old_comment->comment_date_gmt,
						'comment_content'      => $old_comment->comment_content,
						'comment_karma'        => $old_comment->comment_karma,
						'comment_approved'     => $old_comment->comment_approved,
						'comment_agent'        => $old_comment->comment_agent,
						'comment_type'         => $old_comment->comment_type,
						'comment_parent'       => 0,
						'user_id'              => $old_comment->user_id,
					] );

					if ( ! $new_comment_id ) {
						continue;
					}

					$meta = get_comment_meta( $old_comment->comment_ID );
					foreach ( $meta as $meta_key => $values ) {
						foreach ( $values as $value ) {
							add_comment_meta(
								$new_comment_id,
								$meta_key,
								maybe_unserialize( $value )
							);
						}
					}
				}

				/** @var TaskAttachment[] $attachments */
				$attachments = ( new TaskAttachmentCollection([
					'per_page' => -1,
					'where'    => [
						[
							'key'   => 'task_id',
							'value' => $old_task_id,
						],
					],
				]) )->get_results();
				foreach ( $attachments as $attachment ) {
					$attachment->set_task_id( $task_id );
					$attachment->set_id( 0 );
					$attachment->save();
				}

				/** @var TaskChecklistGroup[] $checklist_groups */
				$checklist_groups = ( new TaskChecklistGroupCollection([
					'per_page' => -1,
					'where'    => [
						[
							'key'   => 'card_id',
							'value' => $old_card_id,
						],
					],
				]) )->get_results();

				$checklist_groups_map = [];
				foreach ( $checklist_groups as $checklist_group ) {
					$old_checklist_group_id = $checklist_group->get_id();
					$checklist_group->set_card_id( $card->get_id() );
					$checklist_group->set_id( 0 );
					$checklist_group->save();
					$checklist_groups_map[ $old_checklist_group_id ] = $checklist_group->get_id();
				}

				$checklists = ( new TaskChecklistCollection([
					'per_page' => -1,
					'where'    => [
						[
							'key'   => 'card_id',
							'value' => $old_card_id,
						],
					],
				]) );
				foreach ( $checklists as $checklist ) {
					$checklist->set_card_id( $card->get_id() );
					$checklist->set_checklist_group_id( $checklist_groups_map[ $checklist->get_checklist_group_id() ] ?? 0 );
					$checklist->set_id( 0 );
					$checklist->save();
				}

				$sse->emitEvent( [
					'type'    => 'message',
					'message' => sprintf(
					// translators: %d: Old Card ID.
						__( 'Card #%d duplicated successfully.', 'gemboards' ),
						$old_card_id ),
				]);
			}

			$sse->emitEvent( [
				'type' => 'completed',
			], true );
		} );
	}

	public function get_board_columns( array $payload ) {
		if ( empty($payload['board_id']) ) {
			wp_send_json_error( [
				'message' => __( 'Board ID is required.', 'gemboards' ),
			] );
		}

		$board_id = $payload['board_id'];
		$board    = Helper::get_board($board_id);

		wp_send_json_success( array_map(fn( $column) => [
			'id'    => $column->get_id(),
			'title' => $column->get_title(),
		], $board->get_columns()) );
	}

	private function get_board_array( \GemBoards\Entities\Board $board ): array {
		return array_merge( $board->get_data(), [
			'id'                  => $board->get_id(),
			'completed_column_id' => $board->get_completed_column_id(),
			'created_at'          => $board->get_date_created_at() ? $board->get_date_created_at()->format( 'Y-m-d H:i:s' ) : null,
			'updated_at'          => $board->get_date_updated_at() ? $board->get_date_updated_at()->format( 'Y-m-d H:i:s' ) : null,
		] );
	}
}
