<?php
declare( strict_types=1 );

namespace FiboFilters\Util;

use FiboFilters\Config\Env;

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

/**
 * Class DbUtil
 */
class DbUtil {
	/** @var Cache */
	private $cache;

	public function __construct( Cache $cache ) {
		$this->cache = $cache;
	}

	/**
	 * Get default collate
	 *
	 * @param string $context Collate context.
	 */
	public function get_collate( string $context = '' ): string {
		global $wpdb;

		$sql     = '';
		$collate = '';
		$charset = '';
		if ( $wpdb->has_cap( 'collation' ) ) {
			if ( ! empty( $wpdb->charset ) ) {
				$charset = $wpdb->charset;
			}
			if ( ! empty( $wpdb->collate ) ) {
				$collate = $wpdb->collate;
			}
		}

		$charset = apply_filters( 'fibofilters/db/charset', $charset, $context );
		$collate = apply_filters( 'fibofilters/db/collation', $collate, $context );

		if ( ! empty( $charset ) ) {
			$sql .= ' DEFAULT CHARACTER SET ' . $charset;
		}

		if ( ! empty( $collate ) ) {
			$sql .= ' COLLATE ' . $collate;
		}

		return apply_filters( 'fibofilters/db/collation/sql', $sql, $context );
	}

	/**
	 * Get all DB tables belong to the plugin
	 *
	 * @param bool $network_scope Get tables in whole network.
	 */
	public function get_all_plugin_tables( bool $network_scope = false ): array {
		global $wpdb;

		$plugin_tables = [];

		$tables = $wpdb->get_col( 'SHOW TABLES' );

		if ( ! empty( $tables ) && is_array( $tables ) ) {
			foreach ( $tables as $table ) {
				if ( ! empty( $table ) && is_string( $table ) && strpos( $table, Env::$plugin_prefix ) !== false ) {
					$plugin_tables[] = $table;
				}
			}
		}

		if ( ! ( is_multisite() && $network_scope ) ) {
			$blog_scope_tables = [];
			$prefix            = $wpdb->get_blog_prefix();

			foreach ( $plugin_tables as $name ) {
				if ( strpos( $name, $prefix . Env::$plugin_prefix ) === 0 ) {
					$blog_scope_tables[] = $name;
				}
			}

			$plugin_tables = $blog_scope_tables;
		}

		return $plugin_tables;
	}

	/**
	 * Get table suffix
	 *
	 * @param string $index_type Index type.
	 * @param string $language Language.
	 */
	public function get_table_suffix( string $index_type, string $language = '' ): string {
		$suffix = '';

		if ( ! empty( $language ) ) {
			$suffix .= '_' . str_replace( '-', '_', $language );
		}

		$suffix .= '_' . $index_type;

		return $suffix;
	}

	/**
	 * Get table name
	 *
	 * @param string $type Table type.
	 * @param string $index_type Index type.
	 * @param string $language Data type language.
	 */
	public function get_table_name( string $type, string $index_type = 'main', string $language = '' ): string {
		global $wpdb;

		$name   = '';
		$suffix = $this->get_table_suffix( $index_type, $language );

		switch ( $type ) {
			case 'filters_valuelist':
				$name = $wpdb->fibofilters_valuelist . $suffix;
				break;
			case 'filters_doclist':
				$name = $wpdb->fibofilters_doclist . $suffix;
				break;
			case 'filters_sources':
				$name = $wpdb->fibofilters_sources . $suffix;
				break;
			case 'filters_descriptors':
				$name = $wpdb->fibofilters_descriptors . $suffix;
				break;
		}

		return $name;
	}

	/**
	 * Remove all database tables created by this plugin
	 *
	 * @param bool $network_scope Delete tables in whole network.
	 */
	public function delete_database_tables( bool $network_scope = false ): void {
		global $wpdb;

		// DB tables.
		$tables = $this->get_all_plugin_tables( $network_scope );

		if ( ! empty( $tables ) ) {
			foreach ( $tables as $table ) {
				$wpdb->query( "DROP TABLE IF EXISTS $table" ); // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
			}
		}
	}

	/**
	 * Check if table exist
	 *
	 * @param string $table_name Table name.
	 * @param bool   $is_indexing Is indexing in progress.
	 *
	 * @return bool
	 */
	public function is_table_exists( string $table_name, bool $is_indexing = false ): bool {
		global $wpdb;

		if ( ! $is_indexing ) {
			$cache = $this->cache->get( 'table_exists', 'database' );
			if ( is_array( $cache ) ) {
				return in_array( $table_name, $cache, true );
			}
		}

		$exist = false;
		$wpdb->hide_errors();

		$result = $wpdb->get_col( $wpdb->prepare( 'SHOW TABLES LIKE %s', $wpdb->prefix . 'fibofilters_%' ) );

		if ( is_array( $result ) && in_array( $table_name, $result, true ) ) {
			$exist = true;
		}

		$wpdb->show_errors();

		if ( is_array( $result ) && ! empty( $result ) ) {
			$this->cache->set( 'table_exists', $result, 'database' );
		}

		return $exist;
	}

	/**
	 * Remove indexer options
	 */
	public function remove_indexer_options(): void {
		global $wpdb;

		/**
		 * Filters index options
		 * batch:
		 * - fibofilters_build_filters_index__bfc6f612423866e94a9fd52889a635b8
		 * lock:
		 * - fibofilters_build_filters_index_process_lock
		 */

		$table  = $wpdb->options;
		$column = 'option_name';

		if ( is_multisite() ) {
			$table  = $wpdb->sitemeta;
			$column = 'meta_key';
		}

		// phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared
		$wpdb->query(
			"DELETE
			FROM {$table}
			WHERE {$column} LIKE 'fibofilters_build_filters_index_batch_%' OR
			{$column} LIKE 'fibofilters_build_filters_index_process_lock'"
		);
		// phpcs:enable WordPress.DB.PreparedSQL.InterpolatedNotPrepared
	}
}
