<?php

namespace GemBoards\Entities;

use GemBoards\Classes\AbstractEntity;
use GemBoards\Classes\Datetime;
use GemBoards\Classes\Exception\GemboardsInvalidArgumentException;
use GemBoards\Collections\CardAssigneeCollection;
use GemBoards\Collections\TaskAttachmentCollection;
use GemBoardsPro\Collections\CustomFieldCollection;
use GemBoardsPro\Collections\TaskChecklistCollection;
use GemBoardsPro\Collections\TaskChecklistGroupCollection;
use GemBoards\factories\CardFactory;
use GemBoards\Utils\Helper;
use GemBoardsPro\Entities\TaskChecklist;
use GemBoardsPro\Entities\TaskChecklistGroup;


class Card extends AbstractEntity {

	protected string $table       = 'gemboards_cards';
	protected string $object_type = 'card';

	protected array $data = [
		'task_id'      => 0,
		'board_id'     => 0,
		'column_id'    => 0,
		'sprint_id'    => 0,
		'sort_order'   => 1,
		'is_completed' => false,
		'archived'     => false,
		'story_point'  => 0,
		'due_date'     => null,
		'updated_at'   => '',
		'completed_at' => '',
	];

	protected array $assignees     = [];
	protected bool $read_assignees = false;

	protected array $attachments     = [];
	protected bool $read_attachments = false;

	protected array $checklists     = [];
	protected bool $read_checklists = false;

	protected array $checklist_groups     = [];
	protected bool $read_checklist_groups = false;

	protected array $custom_fields    = [];
	protected bool $read_custom_fields = false;

	public static function factory(): CardFactory {
		return CardFactory::init();
	}

	public function get_task_id( string $context = 'view' ): int {
		return (int) $this->get_prop( 'task_id', $context );
	}

	public function get_board_id( string $context = 'view' ): int {
		return (int) $this->get_prop( 'board_id', $context );
	}

	public function get_board( string $context = 'view' ) {
		return Helper::get_board( $this->get_board_id() );
	}

	public function get_column_id( string $context = 'view' ): int {
		return (int) $this->get_prop( 'column_id', $context );
	}

	public function get_sprint_id( string $context = 'view' ): int {
		return (int) $this->get_prop( 'sprint_id', $context );
	}

	public function get_sort_order( string $context = 'view' ): int {
		return (int) $this->get_prop( 'sort_order', $context );
	}

	public function get_date_updated( string $context = 'view' ) {
		return $this->get_prop( 'updated_at', $context );
	}

	public function get_date_completed( string $context = 'view' ) {
		return $this->get_prop( 'completed_at', $context );
	}

	public function is_completed( string $context = 'view' ): bool {
		return (bool) $this->get_prop( 'is_completed', $context );
	}

	protected function get_is_completed( string $context = 'view' ): bool {
		return (bool) $this->get_prop( 'is_completed', $context );
	}

	public function is_archived( string $context = 'view' ) {
		return (bool) $this->get_prop( 'archived', $context );
	}

	protected function get_archived( string $context = 'view' ): bool {
		return (bool) $this->get_prop( 'archived', $context );
	}

	public function get_story_point( string $context = 'view' ): int {
		return (int) $this->get_prop( 'story_point', $context );
	}

	/**
	 * @param string $context
	 *
	 * @return Datetime|null
	 */
	public function get_due_date( string $context = 'view' ) {
		return $this->get_prop( 'due_date', $context );
	}

	public function get_task() {
		return get_post( $this->get_task_id() );
	}

	/**
	 * Get the column entity associated with this card.
	 *
	 * @return Column|false
	 */
	public function get_column() {
		$column_id = $this->get_column_id();

		if ( ! $column_id ) {
			return false;
		}

		return Helper::get_column( $column_id );
	}

	/**
	 * @param bool $force_read
	 *
	 * @return CardAssignee[]
	 */
	public function get_assignees( bool $force_read = false ): array {
		if ( ! $this->read_assignees || $force_read ) {
			$this->read_assignees();
		}

		return $this->assignees;
	}

	protected function read_assignees() {
		$this->assignees = [];

		try {
			$assignees            = new CardAssigneeCollection( [
				'per_page' => - 1,
				'where'    => [
					[
						'key'   => 'card_id',
						'value' => $this->get_id(),
					],
				],
			] );
			$this->assignees      = $assignees->get_results();
			$this->read_assignees = true;
		} catch ( GemboardsInvalidArgumentException $e ) {
			Helper::error_log( $e->getMessage() );
		}
	}

	/**
	 * @param bool $force_read
	 *
	 * @return TaskAttachment[]
	 */
	public function get_attachments( bool $force_read = false ): array {
		if ( ! $this->read_attachments || $force_read ) {
			$this->read_attachments();
		}

		return $this->attachments;
	}

	protected function read_attachments() {
		$this->attachments = [];

		try {
			$assignees              = new TaskAttachmentCollection( [
				'per_page' => - 1,
				'where'    => [
					[
						'key'   => 'task_id',
						'value' => $this->get_task_id(),
					],
				],
			] );
			$this->attachments      = $assignees->get_results();
			$this->read_attachments = true;
		} catch ( GemboardsInvalidArgumentException $e ) {
			Helper::error_log( $e->getMessage() );
		}
	}

	/**
	 * @param bool $force_read
	 *
	 * @return TaskChecklist[]
	 */
	public function get_checklists( bool $force_read = false ): array {
		if ( ! Helper::has_pro() ) {
			return [];
		}
		if ( ! $this->read_checklists || $force_read ) {
			$this->read_checklists();
		}

		return $this->checklists;
	}

	protected function read_checklists() {
		$this->checklists = [];

		try {
			$assignees             = new TaskChecklistCollection( [
				'per_page' => - 1,
				'where'    => [
					[
						'key'   => 'card_id',
						'value' => $this->get_id(),
					],
				],
			] );
			$this->checklists      = $assignees->get_results();
			$this->read_checklists = true;
		} catch ( GemboardsInvalidArgumentException $e ) {
			Helper::error_log( $e->getMessage() );
		}
	}

	/**
	 * @param bool $force_read
	 *
	 * @return TaskChecklist[]
	 */
	public function get_custom_fields( bool $force_read = false ): array {
		if ( ! Helper::has_pro() ) {
			return [];
		}
		if ( ! $this->read_custom_fields || $force_read ) {
			$this->read_custom_fields();
		}

		return $this->custom_fields;
	}

	protected function read_custom_fields() {
		$this->custom_fields = [];

		try {
			$custom_fields             = new CustomFieldCollection( [
				'per_page' => - 1,
				'where'    => [
					[
						'key'   => 'board_id',
						'value' => $this->get_board_id(),
					],
				],
			] );
			$this->custom_fields      = $custom_fields->get_results();
			$this->read_custom_fields = true;
		} catch ( GemboardsInvalidArgumentException $e ) {
			Helper::error_log( $e->getMessage() );
		}
	}

	/**
	 * @param bool $force_read
	 *
	 * @return TaskChecklistGroup[]
	 */
	public function get_checklist_groups( bool $force_read = false ): array {
		if ( ! Helper::has_pro() ) {
			return [];
		}

		if ( ! $this->read_checklist_groups || $force_read ) {
			$this->read_checklist_groups();
		}

		return $this->checklist_groups;
	}

	protected function read_checklist_groups() {
		$this->checklist_groups = [];

		try {
			$groups = ( new TaskChecklistGroupCollection( [
				'per_page' => - 1,
				'where'    => [
					[
						'key'   => 'card_id',
						'value' => $this->get_id(),
					],
				],
			] ) )->get_results();

			$this->checklist_groups      = $groups;
			$this->read_checklist_groups = true;
		} catch ( GemboardsInvalidArgumentException $e ) {
			Helper::error_log( $e->getMessage() );
		}
	}

	public function set_task_id( int $value ) {
		$this->set_prop( 'task_id', $value );
	}

	public function set_board_id( int $value ) {
		$this->set_prop( 'board_id', $value );
	}

	public function set_column_id( int $value ) {
		$this->set_prop( 'column_id', $value );
	}

	public function set_sprint_id( int $value ) {
		$this->set_prop( 'sprint_id', $value );
	}

	public function set_sort_order( int $value ) {
		$this->set_prop( 'sort_order', $value );
	}

	public function set_is_completed( bool $value ) {
		$this->set_prop( 'is_completed', $value );
	}

	public function set_archived( bool $value ) {
		$this->set_prop( 'archived', $value );
	}

	public function set_story_point( int $value ) {
		$this->set_prop( 'story_point', $value );
	}

	public function set_due_date( ?string $value ) {
		$this->set_date_prop( 'due_date', $value );
	}

	public function set_completed_at( ?string $value ) {
		$this->set_date_prop( 'completed_at', $value );
	}

	public function create() {
		parent::create();
		do_action( 'gemboards/card/created', $this->get_id() );
	}

	public function update() {
		$changes    = $this->get_changes();
		$old_values = [];
		foreach ( $changes as $key => $value ) {
			$old_values[ $key ] = $this->data[ $key ];
		}
		parent::update();
		foreach ( $changes as $key => $value ) {
			do_action( "gemboards/card/{$key}_updated", $this->get_id(), $value, $old_values[ $key ] );
		}
	}

}
