<?php

namespace Dev4Press\Plugin\BreadcrumbsPress\Expand;

use Dev4Press\Plugin\BreadcrumbsPress\Basic\Helper;
use Dev4Press\Plugin\BreadcrumbsPress\Data\Crumb;
use Dev4Press\Plugin\BreadcrumbsPress\Data\Post;
use Dev4Press\Plugin\BreadcrumbsPress\Data\PostType;
use Dev4Press\Plugin\BreadcrumbsPress\Data\Taxonomy;
use Dev4Press\Plugin\BreadcrumbsPress\Data\Term;
use Dev4Press\Plugin\BreadcrumbsPress\Extend\Plugin;
use WP_Term;

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

class GDContentTools extends Plugin {
	public static function instance() : GDContentTools {
		static $instance = null;

		if ( ! isset( $instance ) ) {
			$instance = new GDContentTools();
			$instance->run();
		}

		return $instance;
	}

	/**
	 * @inheritDoc
	 */
	public function build( $breadcrumbs ) : array {
		if ( $this->q()->is_cpt_tax_intersection() ) {
			$intersection = gdcet_get_archive_intersections();

			if ( $intersection->method == 'simple' ) {
				$breadcrumbs = $this->get_taxonomy_term_archive_page();
			} else if ( $intersection->method == 'custom' ) {
				$breadcrumbs = $this->get_taxonomy_intersect_archive_page();
			}
		} else if ( $this->q()->is_cpt_date_intersection() ) {
			if ( $this->q()->is_year() ) {
				$breadcrumbs = $this->get_date_year_page();
			} else if ( $this->q()->is_month() ) {
				$breadcrumbs = $this->get_date_month_page();
			} else if ( $this->q()->is_day() ) {
				$breadcrumbs = $this->get_date_day_page();
			}
		} else if ( $this->q()->is_cpt_author_intersection() ) {
			$breadcrumbs = $this->get_author_archive_page();
		}

		return $breadcrumbs;
	}

	/**
	 * @param null|string $post_type
	 * @param int|null    $term_id
	 * @param string|null $taxonomy
	 *
	 * @return Crumb[]
	 */
	public function get_taxonomy_term_archive_page( $post_type = null, $term_id = null, $taxonomy = null ) : array {
		$post_type = is_null( $post_type ) ? $this->q()->get_post_type() : $post_type;
		$term_id   = is_null( $term_id ) ? $this->q()->get_term_id() : absint( $term_id );
		$taxonomy  = is_null( $taxonomy ) ? $this->q()->get_taxonomy() : absint( $taxonomy );
		$term      = get_term( $term_id, $taxonomy );

		if ( $term instanceof WP_Term ) {
			return $this->term_single( $post_type, $term );
		}

		return array();
	}

	/**
	 * @param null|string    $post_type
	 * @param null|WP_Term[] $terms
	 *
	 * @return Crumb[]
	 */
	public function get_taxonomy_intersect_archive_page( $post_type = null, $terms = null ) : array {
		$post_type = is_null( $post_type ) ? $this->q()->get_post_type() : $post_type;

		if ( is_null( $terms ) ) {
			$_post        = PostType::instance( $post_type );
			$intersection = gdcet_get_archive_intersections();

			$labels = array();
			foreach ( $intersection->taxonomies as $tax ) {
				$term = get_term_by( 'slug', $intersection->terms[ $tax ], $tax );

				if ( $term instanceof WP_Term ) {
					$_type = Taxonomy::instance( $tax );
					$_term = Term::instance( $term );

					$labels[] = $_term->title() . " " . $_type->get_label_singular();
				}
			}

			return array(
				'home'  => $this->b()->home(),
				'posts' => $this->c()->crumbs_post_type_archive( $_post ),
				'terms' => $this->b()->crumb( array(
					'type'    => 'term',
					'title'   => $this->b()->title( 'core_var_archives', join( ', ', $labels ) ),
					'current' => true,
				) ),
			);
		}

		return array();
	}

	/**
	 * @param null|string $post_type
	 * @param null|int    $author
	 * @param bool        $use_template
	 *
	 * @return Crumb[]
	 */
	public function get_author_archive_page( $post_type = null, $author = null, $use_template = true ) : array {
		$post_type = is_null( $post_type ) ? $this->q()->get_post_type() : $post_type;
		$author    = is_null( $author ) ? $this->q()->get_author() : absint( $author );

		$value = Helper::instance()->user_title( $author );

		return array(
			'home'   => $this->b()->home(),
			'posts'  => $this->b()->post_type_archive( $post_type, false ),
			'author' => $this->b()->crumb( array(
				'type'    => 'author',
				'title'   => $use_template ? $this->b()->title( 'core_author_archives', $value ) : $value,
				'display' => $use_template ? $this->b()->display( 'core_author_archives' ) : '%title%',
				'url'     => gdcet_get_author_archive_link( $post_type, $author ),
				'current' => true,
			) ),
		);
	}

	/**
	 * @param null|string $post_type
	 * @param null|int    $year
	 * @param bool        $current
	 *
	 * @return Crumb[]
	 */
	public function get_date_year_page( $post_type = null, $year = null, $current = true ) : array {
		$post_type = is_null( $post_type ) ? $this->q()->get_post_type() : $post_type;
		$year      = is_null( $year ) ? $this->q()->get_year() : intval( $year );

		return array(
			'home'      => $this->b()->home(),
			'posts'     => $this->b()->post_type_archive( $post_type, false ),
			'date-year' => $this->b()->crumb( array(
				'type'    => 'date-year',
				'title'   => $current ? $this->b()->title( 'core_date_archives', $year ) : $year,
				'display' => $current ? $this->b()->display( 'core_date_archives' ) : '%title%',
				'url'     => gdcet_get_date_archive_link( $post_type, $year ),
				'current' => $current,
			) ),
		);
	}

	/**
	 * @param null|string $post_type
	 * @param null|int    $year
	 * @param null|int    $month
	 * @param bool        $use_template
	 *
	 * @return Crumb[]
	 */
	public function get_date_month_page( $post_type = null, $year = null, $month = null, $use_template = true ) : array {
		$post_type = is_null( $post_type ) ? $this->q()->get_post_type() : $post_type;
		$year      = is_null( $year ) ? $this->q()->get_year() : intval( $year );
		$month     = is_null( $month ) ? $this->q()->get_month() : absint( $month );

		$month = $month < 1 || $month > 12 ? 1 : $month;
		$value = Helper::instance()->month_title( $year, $month );

		$breadcrumbs = $this->get_date_year_page( $post_type, $year, false );
		$breadcrumbs['date-year']->set_current( false );
		$breadcrumbs['date-month'] = $this->b()->crumb( array(
			'type'    => 'date-month',
			'title'   => $use_template ? $this->b()->title( 'core_date_archives', $value ) : str_pad( $month, 2, '0', STR_PAD_LEFT ),
			'display' => $use_template ? $this->b()->display( 'core_date_archives' ) : '%title%',
			'url'     => gdcet_get_date_archive_link( $post_type, $year, $month ),
			'current' => true,
		) );

		return $breadcrumbs;
	}

	/**
	 * @param null|string $post_type
	 * @param null|int    $year
	 * @param null|int    $month
	 * @param null|int    $day
	 * @param bool        $use_template
	 *
	 * @return Crumb[]
	 */
	public function get_date_day_page( $post_type = null, $year = null, $month = null, $day = null, $use_template = true ) : array {
		$post_type = is_null( $post_type ) ? $this->q()->get_post_type() : $post_type;
		$year      = is_null( $year ) ? $this->q()->get_year() : intval( $year );
		$month     = is_null( $month ) ? $this->q()->get_month() : absint( $month );
		$day       = is_null( $day ) ? $this->q()->get_day() : absint( $day );

		$month = $month < 1 || $month > 12 ? 1 : $month;
		$day   = $day < 1 || $day > 31 ? 1 : $day;

		$value = Helper::instance()->day_title( $year, $month, $day );

		$breadcrumbs = $this->get_date_month_page( $post_type, $year, $month, false );
		$breadcrumbs['date-month']->set_current( false );
		$breadcrumbs['date-day'] = $this->b()->crumb( array(
			'type'    => 'date-day',
			'title'   => $use_template ? $this->b()->title( 'core_date_archives', $value ) : str_pad( $day, 2, '0', STR_PAD_LEFT ),
			'display' => $use_template ? $this->b()->display( 'core_date_archives' ) : '%title%',
			'url'     => gdcet_get_date_archive_link( $post_type, $year, $month, $day ),
			'current' => true,
		) );

		return $breadcrumbs;
	}

	/**
	 * @param string      $post_type
	 * @param \WP_Term    $term
	 * @param null|string $path
	 *
	 * @return Crumb[]
	 */
	public function term_single( $post_type, $term, $path = null ) : array {
		$_post = PostType::instance( $post_type );
		$_type = Taxonomy::instance( $term->taxonomy );
		$_term = Term::instance( $term );

		$_crumb_home = $this->b()->home();
		$_crumb_term = $this->crumbs_term( $post_type, $_term, $_type, true );

		$path      = is_null( $path ) ? $_type->get_path() : $path;
		$hierarchy = $_type->get_hierarchy();

		$crumbs = array();

		if ( $path == 'taxonomy' && $hierarchy != 'no' ) {
			if ( $hierarchy == 'full' ) {
				$crumbs = $this->get_path_tax_full( $_post, $_type, $_term, $_crumb_home, $_crumb_term );
			} else if ( $hierarchy == 'parent' && $_term->has_parent() ) {
				$crumbs = $this->get_path_tax_parent( $_post, $_type, $_term, $_crumb_home, $_crumb_term );
			}
		}

		if ( empty( $crumbs ) ) {
			$crumbs = $this->get_path_tax_basic( $_post, $_type, $_term, $_crumb_home, $_crumb_term );
		}

		return $crumbs;
	}

	/**
	 * @param string   $post_type
	 * @param Term     $term
	 * @param Taxonomy $type
	 * @param bool     $current
	 *
	 * @return Crumb
	 */
	public function crumbs_term( $post_type, $term, $type, $current = false ) : Crumb {
		return $this->b()->crumb( array(
			'type'    => 'term',
			'title'   => $current ? $this->b()->title( 'tax_' . $term->get_taxonomy(), $term->title(), '%value%', array( '%tax%' => $type->get_label_singular() ) ) : $term->title(),
			'display' => $current ? $this->b()->display( 'tax_' . $term->get_taxonomy() ) : '%title%',
			'url'     => $term->url_with_post_type( $post_type ),
			'current' => $current,
			'id'      => $term->get_id(),
		) );
	}

	/**
	 * @param PostType $_type
	 * @param Post     $_post
	 * @param Crumb    $_crumb_home
	 * @param Crumb    $_crumb_post
	 * @param string   $path
	 * @param string   $taxonomy
	 *
	 * @return Crumb[]
	 */
	public function post_single( $_type, $_post, $_crumb_home, $_crumb_post, $path, $taxonomy ) : array {
		$crumbs = array();

		switch ( $path ) {
			case 'cpt_author':
				if ( $_type->has_cpt_author() ) {
					$crumbs = $this->get_path_cpt_author( $_type, $_post, $_crumb_home, $_crumb_post );
				}
				break;
			case 'cpt_day':
				if ( $_type->has_cpt_day() ) {
					$crumbs = $this->get_path_cpt_day( $_type, $_post, $_crumb_home, $_crumb_post );
				}
				break;
			case 'cpt_month':
				if ( $_type->has_cpt_month() ) {
					$crumbs = $this->get_path_cpt_month( $_type, $_post, $_crumb_home, $_crumb_post );
				}
				break;
			case 'cpt_year':
				if ( $_type->has_cpt_year() ) {
					$crumbs = $this->get_path_cpt_year( $_type, $_post, $_crumb_home, $_crumb_post );
				}
				break;
			case 'cpt_intersection':
				if ( $_type->has_cpt_intersection() && $_type->is_taxonomy_valid( $taxonomy ) ) {
					$term = $_post->get_first_term( $taxonomy );

					if ( $term !== false ) {
						$chain = Helper::instance()->chain_terms( $term->term_id, $taxonomy );
						$chain = array_reverse( $chain );

						$crumbs = array(
							'home'              => $_crumb_home,
							'post_type_archive' => $this->c()->crumbs_post_type_archive( $_type ),
						);

						for ( $i = 0; $i < count( $chain ); $i ++ ) {
							$crumbs[ 'term_' . $chain[ $i ]->term_id ] = $this->c()->crumbs_term( $chain[ $i ], $_post, true );
						}

						$crumbs['post'] = $_crumb_post;
					}
				}
				break;
		}

		return $crumbs;
	}

	/**
	 * @param array    $paths
	 * @param PostType $_type
	 * @param Post     $_post
	 * @param Crumb    $_crumb_home
	 * @param Crumb    $_crumb_post
	 * @param array    $generate
	 *
	 * @return array
	 */
	public function post_multi( $paths, $_type, $_post, $_crumb_home, $_crumb_post, $generate ) : array {
		if ( $generate['author'] && $_type->has_cpt_author() ) {
			$paths['cpt_author'] = $this->get_path_cpt_author( $_type, $_post, $_crumb_home, $_crumb_post );
		}

		if ( $generate['date'] ) {
			if ( $_type->has_cpt_day() ) {
				$paths['cpt_day'] = $this->get_path_cpt_day( $_type, $_post, $_crumb_home, $_crumb_post );
			}

			if ( $_type->has_cpt_month() ) {
				$paths['cpt_month'] = $this->get_path_cpt_month( $_type, $_post, $_crumb_home, $_crumb_post );
			}

			if ( $_type->has_cpt_year() ) {
				$paths['cpt_year'] = $this->get_path_cpt_year( $_type, $_post, $_crumb_home, $_crumb_post );
			}
		}

		if ( $generate['terms'] && $_type->has_cpt_intersection() ) {
			foreach ( $_type->get_taxonomies_names() as $tax ) {
				$_terms = $_post->get_terms( $tax );

				foreach ( $_terms as $term ) {
					$chain = Helper::instance()->chain_terms( $term->term_id, $tax );
					$chain = array_reverse( $chain );
					$_key  = 'cpt_taxonomy_' . $tax . '_' . $term->term_id;

					$paths[ $_key ] = array(
						'home'              => $_crumb_home,
						'post_type_archive' => $this->c()->crumbs_post_type_archive( $_type ),
					);

					for ( $i = 0; $i < count( $chain ); $i ++ ) {
						$paths[ $_key ][ 'term_' . $chain[ $i ]->term_id ] = $this->c()->crumbs_term( $chain[ $i ], $_post, true );
					}

					$paths[ $_key ]['post'] = $_crumb_post;
				}
			}
		}

		return $paths;
	}

	/**
	 * @param PostType $_type
	 * @param Post     $_post
	 * @param Crumb    $_crumb_home
	 * @param Crumb    $_crumb_post
	 *
	 * @return Crumb[]
	 */
	public function get_path_cpt_author( $_type, $_post, $_crumb_home, $_crumb_post ) : array {
		return array(
			'home'              => $_crumb_home,
			'post_type_archive' => $this->c()->crumbs_post_type_archive( $_type ),
			'author'            => $this->c()->crumbs_post_author( $_post, true ),
			'post'              => $_crumb_post,
		);
	}

	/**
	 * @param PostType $_type
	 * @param Post     $_post
	 * @param Crumb    $_crumb_home
	 * @param Crumb    $_crumb_post
	 *
	 * @return Crumb[]
	 */
	public function get_path_cpt_day( $_type, $_post, $_crumb_home, $_crumb_post ) : array {
		return array(
			'home'              => $_crumb_home,
			'post_type_archive' => $this->c()->crumbs_post_type_archive( $_type ),
			'year'              => $this->c()->crumbs_year( $_post, true ),
			'month'             => $this->c()->crumbs_month( $_post, true ),
			'day'               => $this->c()->crumbs_day( $_post, true ),
			'post'              => $_crumb_post,
		);
	}

	/**
	 * @param PostType $_type
	 * @param Post     $_post
	 * @param Crumb    $_crumb_home
	 * @param Crumb    $_crumb_post
	 *
	 * @return Crumb[]
	 */
	public function get_path_cpt_month( $_type, $_post, $_crumb_home, $_crumb_post ) : array {
		return array(
			'home'              => $_crumb_home,
			'post_type_archive' => $this->c()->crumbs_post_type_archive( $_type ),
			'year'              => $this->c()->crumbs_year( $_post, true ),
			'month'             => $this->c()->crumbs_month( $_post, true ),
			'post'              => $_crumb_post,
		);
	}

	/**
	 * @param PostType $_type
	 * @param Post     $_post
	 * @param Crumb    $_crumb_home
	 * @param Crumb    $_crumb_post
	 *
	 * @return Crumb[]
	 */
	public function get_path_cpt_year( $_type, $_post, $_crumb_home, $_crumb_post ) : array {
		return array(
			'home'              => $_crumb_home,
			'post_type_archive' => $this->c()->crumbs_post_type_archive( $_type ),
			'year'              => $this->c()->crumbs_year( $_post, true ),
			'post'              => $_crumb_post,
		);
	}

	/**
	 * @param PostType $_post
	 * @param Taxonomy $_type
	 * @param Term     $_term
	 * @param Crumb    $_crumb_home
	 * @param Crumb    $_crumb_term
	 *
	 * @return Crumb[]
	 */
	public function get_path_tax_basic( $_post, $_type, $_term, $_crumb_home, $_crumb_term ) : array {
		return array(
			'home'  => $_crumb_home,
			'posts' => $this->c()->crumbs_post_type_archive( $_post ),
			'term'  => $_crumb_term,
		);
	}

	/**
	 * @param PostType $_post
	 * @param Taxonomy $_type
	 * @param Term     $_term
	 * @param Crumb    $_crumb_home
	 * @param Crumb    $_crumb_term
	 *
	 * @return Crumb[]
	 */
	public function get_path_tax_parent( $_post, $_type, $_term, $_crumb_home, $_crumb_term ) : array {
		$parent_term = get_term_by( 'id', $_term->get_parent_id(), $_type->get_name() );
		$_parent     = Term::instance( $parent_term );

		return array(
			'home'   => $_crumb_home,
			'posts'  => $this->c()->crumbs_post_type_archive( $_post ),
			'parent' => $this->crumbs_term( $_post->get_name(), $_parent, $_type ),
			'term'   => $_crumb_term,
		);
	}

	/**
	 * @param PostType $_post
	 * @param Taxonomy $_type
	 * @param Term     $_term
	 * @param Crumb    $_crumb_home
	 * @param Crumb    $_crumb_term
	 *
	 * @return Crumb[]
	 */
	public function get_path_tax_full( $_post, $_type, $_term, $_crumb_home, $_crumb_term ) : array {
		$terms = array_reverse( Helper::instance()->chain_terms( $_term->get_id(), $_term->get_taxonomy() ) );

		$crumbs = array(
			'home'  => $_crumb_home,
			'posts' => $this->c()->crumbs_post_type_archive( $_post ),
		);

		if ( count( $terms ) > 1 ) {
			for ( $i = 0; $i < count( $terms ) - 1; $i ++ ) {
				$_parent = Term::instance( $terms[ $i ] );

				$crumbs[ 'term_' . $_parent->get_id() ] = $this->crumbs_term( $_post->get_name(), $_parent, $_type );
			}
		}

		$crumbs['term'] = $_crumb_term;

		return $crumbs;
	}

	/**
	 * @inheritDoc
	 */
	public function complete( $breadcrumbs ) : array {
		return $breadcrumbs;
	}

	public function ready() {

	}
}
