<?php

namespace BwWinner;

class Entity_Manager {

	private $group = "bw_winner";

	public function __construct() {

	}

	// ----------------------------------------------------------------------------
	// Company
	// ----------------------------------------------------------------------------
	public function get_company ( $company_id ) {
		$company = wp_cache_get( "bw_companies_{$company_id}", $this->group );

		if ( $company === false ) {
			$company = $this->get_entity( $company_id, 'company' );
		}

		return $company;
	}

	public function update_company ( $company ) {

		if ( $this->update_entity( $company, 'company' ) ) {

			wp_cache_delete( "bw_companies_{$company['id']}", $this->group );
			return true;

		}
		return false;
	}


	// ----------------------------------------------------------------------------
	// Brand
	// ----------------------------------------------------------------------------
	public function get_brand ( $brand_id ) {
		$brand = wp_cache_get( "bw_brands_{$brand_id}", $this->group );

		if ( $brand === false ) {
			$brand = $this->get_entity( $brand_id, 'brand' );
		}

		return $brand;
	}

	public function update_brand ( $brand ) {

		if ( $this->update_entity( $brand, 'brand' ) ) {

			wp_cache_delete( "bw_brands_{$brand['id']}", $this->group );
			return true;
			
		}
		return false;
	}


	// ----------------------------------------------------------------------------
	// Product
	// ----------------------------------------------------------------------------
	public function get_product ( $product_id ) {
		$product = wp_cache_get( "bw_products_{$product_id}", $this->group );

		if ( $product === false ) {
			$product = $this->get_entity( $product_id, 'product' );
		}

		return $product;
	}

	public function update_product ( $product ) {

		if ( $this->update_entity( $product, 'product' ) ) {

			wp_cache_delete( "bw_products_{$product['id']}", $this->group );
			return true;
			
		}
		return false;
	}


	// ----------------------------------------------------------------------------
	// Product Entries
	// ----------------------------------------------------------------------------
	public function delete_product_entries ( $product_id, $excludes = array() ) {

		global $wpdb;

		$query = $wpdb->prepare( "DELETE FROM {$wpdb->prefix}bw_winners_entries WHERE product_id = %d", $product_id );

		if ( ! empty( $excludes ) ) {
			$excludes = array_map( 'intval', $excludes );
			$excludes = implode(', ', $excludes);
			$query .= $wpdb->prepare( " AND id NOT IN ( {$excludes} )", $excludes );
		}

		$wpdb->query( $query );

		if ( $wpdb->last_error ) {
			trigger_error( $wpdb->last_error, E_USER_WARNING );
			return false;
		}
		
		wp_cache_delete( "bw_products_{$product_id}", $this->group );
		return true;
	}

	public function insert_entry ( $entry ) {

		if ( ! isset( $entry['product_id'] ) ) return false;
		if ( ! isset( $entry['year'] ) ) return false;
		if ( ! isset( $entry['score'] ) ) return false;

		global $wpdb;

		$wpdb->query( $wpdb->prepare(
			"INSERT INTO {$wpdb->prefix}bw_winners_entries (year, score, product_id) VALUES (%d, %d, %d)",
			$entry['year'],
			$entry['score'],
			$entry['product_id']
		) );

		if ( $wpdb->last_error ) {
			trigger_error( $wpdb->last_error, E_USER_WARNING );
			return false;
		}

		wp_cache_delete( "bw_products_{$entry['product_id']}", $this->group );

		return true;
	}

	public function update_entry ( $entry ) {

		if ( ! isset( $entry['id'] ) ) return false;
		if ( ! isset( $entry['product_id'] ) ) return false;

		global $wpdb;

		$column_values = array();
		$values = array();

		$column_map = array(
			'year' => '%d',
			'score' => '%s'
		);
		
		foreach ($column_map as $name => $value) {
			if ( isset( $entry[$name] ) ) {
				$column_values[] = "{$name}={$value}";
				$values[] = $entry[$name];
			}
		}

		if ( empty( $values ) ) return false;

		$column_values = implode( ', ', $column_values );

		$values[] = $entry['id'];
		$values[] = $entry['product_id'];

		$wpdb->query( $wpdb->prepare(
			"UPDATE {$wpdb->prefix}bw_winners_entries SET {$column_values} WHERE id = %d AND product_id = %d",
			$values
		) );

		if ( $wpdb->last_error ) {
			trigger_error( $wpdb->last_error, E_USER_WARNING );
			return false;
		}

		wp_cache_delete( "bw_products_{$entry['product_id']}", $this->group );

		return true;
	}

	// ----------------------------------------------------------------------------
	// Flush this cache group
	// ----------------------------------------------------------------------------
	public function flush_cache () {
		wp_cache_flush_group( $this->group );
	}

	// ----------------------------------------------------------------------------
	// Brand Posts
	// ----------------------------------------------------------------------------
	
	public function get_brand_posts ( $brand_id ) {

		global $wpdb;


		$query = $wpdb->prepare(
			"SELECT post_id FROM {$wpdb->prefix}bw_winners_brand_posts WHERE brand_id = %d",
			array(
				$brand_id
			)
		);

		$results = $wpdb->get_results($query);

		if ( $wpdb->last_error ) {
			return array();
		}

		$post_ids = array();

		foreach ( $results as $result ) {
			$post_ids[] = $result->post_id;
		}

		return get_posts( array( 'post__in' => $post_ids ) );
	}

	public function get_post_brands ( $post_id ) {

		global $wpdb;

		$query = $wpdb->prepare(
			"SELECT brand.id AS id, brand.name AS name 
				FROM {$wpdb->prefix}bw_winners_brand_posts AS post_brand
					INNER JOIN {$wpdb->prefix}bw_winners_brands AS brand ON brand.id = post_brand.brand_id
				WHERE post_id = %d",
			array(
				$post_id
			)
		);

		$results = $wpdb->get_results($query, ARRAY_A);

		if ( $wpdb->last_error ) {
			return array();
		}

		return $results;

	}

	public function update_post_brands ( $post_id, $brands ) {

		global $wpdb;

		$values = array();
		$in = array();

		if ( is_array( $brands ) && count( $brands ) ) {

			foreach ( $brands as $brand ) {
				if ( is_array( $brand ) ) {
					$brand = $brand['id'];
				} else if ( is_object( $brand ) ) {
					$brand = $brand->id;
				}
				
				$values[] = $wpdb->prepare( "(%d, %d)", array( $brand, $post_id ) );
				$in[] = $wpdb->prepare( "%d", $brand );
			}

			$values = implode( ',', $values );
			$in = implode( ',', $in );

			$wpdb->query( "INSERT IGNORE INTO {$wpdb->prefix}bw_winners_brand_posts (brand_id, post_id) VALUES {$values}" );

			$wpdb->query( $wpdb->prepare(
				"DELETE FROM {$wpdb->prefix}bw_winners_brand_posts WHERE post_id=%d AND brand_id NOT IN ({$in})",
				$post_id
			) );
		} else {
			$wpdb->query( $wpdb->prepare(
				"DELETE FROM {$wpdb->prefix}bw_winners_brand_posts WHERE post_id=%d",
				$post_id
			) );
		}
	}

	// ----------------------------------------------------------------------------
	// Create or update a company, brand or product
	// ----------------------------------------------------------------------------
	private function update_entity ( $entity, $entity_type ) {

		if ( ! isset( $entity['id'] ) ) return false;

		global $wpdb;

		$columns = array( 'id' );
		$values = array( '%d' );
		$insert_values = array( $entity['id'] );

		$column_values = array();
		$update_values = array();

		switch ( $entity_type ) {
			case 'company':
				$table = "{$wpdb->prefix}bw_winners_companies";
				$column_map = array(
					'import_id' => '%d',
					'name' => '%s',
					'url' => '%s',
					'email' => '%s'
				);
				break;
			case 'brand':
				$table = "{$wpdb->prefix}bw_winners_brands";
				$column_map = array(
					'company_id' => '%d',
					'name' => '%s',
					'url' => '%s'
				);
				break;	
			case 'product':
				$table = "{$wpdb->prefix}bw_winners_products";
				$column_map = array(
					'brand_id' => '%d',
					'name' => '%s',
					'url' => '%s',
					'type' => '%s',
					'price' => '%s',
					'country' => '%s'
				);
				break;			
			default:
				return false;
				break;
		}

		foreach ($column_map as $name => $value) {
			if ( isset( $entity[$name] ) ) {
				$columns[] = $name;
				$values[] = $value;
				$column_values[] = "{$name}={$value}";
				$insert_values[] = $update_values[] = $entity[$name];
			} else if ( array_key_exists( $name, $entity ) ) {
				$columns[] = $name;
				$values[] = 'NULL';
				$column_values[] = "{$name}={$value}";
				$insert_values[] = $update_values[] = $entity[$name];
			}
		}

		$columns = implode( ', ', $columns );
		$values = implode( ', ', $values );
		$column_values = implode( ', ', $column_values );

		$insert = $wpdb->prepare( 
			"INSERT INTO {$table} ({$columns}) VALUES ({$values})",
			$insert_values
		);

		$update = $wpdb->prepare( 
			"UPDATE {$column_values}",
			$update_values
		);

		$query = "{$insert} ON DUPLICATE KEY {$update}";

		$wpdb->query( $query );

		if ( $wpdb->last_error ) {
			trigger_error( $wpdb->last_error, E_USER_WARNING );
			return false;
		}

		return true;
	}

	// ----------------------------------------------------------------------------
	// Get a company, brand or product
	// ----------------------------------------------------------------------------
	private function get_entity ( $id, $entity_type ) {

		global $wpdb;

		if ( $entity_type !== 'company' && $entity_type !== 'brand' && $entity_type !== 'product' ) {
			return false;
		}

		$select = array(
			"company.id AS company_id",
			"company.name AS company_name",
			"company.url AS company_url",
			"company.email AS company_email"
		);

		$from = array(
			"{$wpdb->prefix}bw_winners_companies AS company",
		);

		if ( $entity_type === 'brand' || $entity_type === 'product' ) {
			$select[] = "brand.id AS brand_id";
			$select[] = "brand.name AS brand_name";
			$select[] = "brand.url AS brand_url";

			$from[] = "INNER JOIN {$wpdb->prefix}bw_winners_brands AS brand ON brand.company_id = company.id";

			if ( $entity_type === 'product' ) {
				$select[] = "product.id AS product_id";
				$select[] = "product.name AS product_name";
				$select[] = "product.url AS product_url";
				$select[] = "product.type AS product_type";
				$select[] = "product.price AS product_price";
				$select[] = "product.country AS product_country";

				$from[] = "INNER JOIN {$wpdb->prefix}bw_winners_products AS product ON product.brand_id = brand.id";
			}
		}

		$select = implode(', ', $select);
		$from = implode(' ', $from);

		if ( $entity_type === 'company' ) {
			$where = 'company.id = %d';
		}
		if ( $entity_type === 'brand' ) {
			$where = 'brand.id = %d';
		}
		if ( $entity_type === 'product' ) {
			$where = 'product.id = %d';
		}

		$query = "SELECT {$select} FROM {$from} WHERE {$where}";

		$entities = $wpdb->get_row( $wpdb->prepare( $query, $id ), ARRAY_A );

		if ( $wpdb->last_error ) {
			trigger_error( $wpdb->last_error, E_USER_WARNING );
			return false;
		}

		if ( ! $entities ) {
			return false;
		}

		$company_id = $entities['company_id'];
		$company = array(
			'id' => $company_id,
			'name' => $entities['company_name'],
			'url' => $entities['company_url'],
			'email' => $entities['company_email']	
		);
		wp_cache_set( "bw_companies_{$company_id}", $company, $this->group );

		if ( $entity_type === 'company' ) {
			return $company;
		}

		$brand_id = $entities['brand_id'];
		$brand = array(
			'id' => $brand_id,
			'company_id' => $company_id,
			'name' => $entities['brand_name'],
			'url' => $entities['brand_url']
		);
		wp_cache_set( "bw_brands_{$brand_id}", $brand, $this->group );

		if ( $entity_type === 'brand' ) {
			return $brand;
		}

		$product_id = $entities['product_id'];
		$product = array(
			'id' => $product_id,
			'brand_id' => $brand_id,
			'company_id' => $company_id,
			'name' => $entities['product_name'],
			'url' => $entities['product_url'],
			'type' => $entities['product_type'],
			'price' => $entities['product_price'],
			'country' => $entities['product_country'],
			'entries' => array()
		);

		$entries = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM {$wpdb->prefix}bw_winners_entries WHERE product_id = %d", $product_id ), ARRAY_A );

		if ( $wpdb->last_error ) {
			trigger_error( $wpdb->last_error, E_USER_WARNING );
			return false;
		}

		if ( $entries ) {
			foreach ( $entries as $entry ) {
				$product['entries'][] = array(
					'id' => $entry['id'],
					'year' => $entry['year'],
					'score' => $entry['score']
				);
			}
		}

		wp_cache_set( "bw_products_{$product_id}", $product, $this->group );
		
		if ( $entity_type === 'product' ) {
			return $product;
		}
		
		return false;
	}
}
