<?php

namespace Gigneo;

if ( ! defined( 'ABSPATH' ) ) {
	exit; // Exit if accessed directly.
}

use WC_Data_Exception;

/**
 * Class Base
 *
 * Plugin base class for Gigneo.
 *
 * @since 0.0.1
 */
class Base {

	/**
	 * The single instance of the class.
	 *
	 * @var Base|null
	 * @since 0.0.1
	 */
	private static $instance = null;

	/**
	 * Constructor for the class.
	 *
	 * @since 0.0.1
	 */
	public function __construct() {
		//Includes
		$this->includes();

		//Initialize Classes
		$this->initialize();
	}

	/**
	 * Include required files.
	 *
	 * @since 0.0.1
	 */
	protected function includes() {
		//Includes
		require_once GIGNEO_DIR_PATH . 'includes/helper-functions.php';
		require_once GIGNEO_DIR_PATH . 'includes/hooks-and-filters.php';
		require_once GIGNEO_DIR_PATH . 'includes/shortcodes.php';
	}

	/**
	 * Initializes all dependent classes.
	 *
	 * @since 0.0.1
	 */
	protected function initialize() {
		Core::instance();           //Core
		Post_Types::instance();     //Post types
		Taxonomies::instance();     //Taxonomies
		Enqueues::instance();       //Enqueues
		Modules::instance();        //Modules
		Theme_Option::instance();   //Theme Options
		Term_Meta::instance();      //Term Metas
		Post_Meta::instance();      //Post Metas
		Ajax::instance();           //Ajax
		Orders::instance();         //Orders
		Invoices::instance();       //Invoices
		Compatibility::instance();  //Compatibility
		Services::instance();       //Services
		Jobs::instance();           //Jobs
		Notifications::instance();  //Notifications
		Withdrawals::instance();    //Withdrawals
	}

	/**
	 * Ensures only one instance of the class is loaded or can be loaded.
	 *
	 * @return Base
	 * @since 0.0.1
	 */
	public static function instance() {
		if ( is_null( self::$instance ) ) {
			self::$instance = new self();
		}

		return self::$instance;
	}

	/**
	 * Load the plugin text domain for translation.
	 *
	 * This function loads the plugin's text domain for translation, allowing for
	 * localization of strings used in the plugin.
	 *
	 * @throws WC_Data_Exception
	 * @since 0.0.1
	 */
	public static function plugin_activate() {
		self::create_pages();        //Create required pages
		self::create_products();     //Create required products
		self::create_tables();       //Create required tables

		if ( class_exists( Notifications::class ) && method_exists( Notifications::class, 'schedule_clean_old_notifications_cron' ) ) {
			Notifications::schedule_clean_old_notifications_cron();
		}
	}

	/**
	 * Create required pages for the plugin.
	 *
	 * This function creates the necessary pages for the plugin if they do not already exist.
	 * It checks for existing pages by their slug and creates them with default content if not found.
	 *
	 * @since 0.0.1
	 */
	private static function create_pages() {
		if ( get_option( '_gigneo_required_pages_status' ) ) {
			return;
		}

		$required_pages = array(
			'dashboard'       => array(
				'title'   => esc_html__( 'Dashboard', 'gigneo' ),
				'slug'    => 'dashboard',
				'content' => '',
			),
			'hire'            => array(
				'title'   => esc_html__( 'Hire', 'gigneo' ),
				'slug'    => 'hire',
				'content' => '[gigneo_hire]',
			),
			'login'           => array(
				'title'   => esc_html__( 'Sign in', 'gigneo' ),
				'slug'    => 'sign-in',
				'content' => '[gigneo_login]',
			),
			'register'        => array(
				'title'   => esc_html__( 'Sign up', 'gigneo' ),
				'slug'    => 'sign-up',
				'content' => '[gigneo_register]',
			),
			'forgot_password' => array(
				'title'   => esc_html__( 'Forgot Password', 'gigneo' ),
				'slug'    => 'forgot-password',
				'content' => '[gigneo_forgot_password]',
			),
			'freelancers'     => array(
				'title'   => esc_html__( 'Freelancers', 'gigneo' ),
				'slug'    => 'freelancers',
				'content' => '[gigneo_freelancers]',
			),
			'services'        => array(
				'title'   => esc_html__( 'Services', 'gigneo' ),
				'slug'    => 'services',
				'content' => '[gigneo_services]',
			),
			'employers'       => array(
				'title'   => esc_html__( 'Employers', 'gigneo' ),
				'slug'    => 'employers',
				'content' => '[gigneo_employers]',
			),
			'jobs'            => array(
				'title'   => esc_html__( 'Jobs', 'gigneo' ),
				'slug'    => 'jobs',
				'content' => '[gigneo_jobs]',
			),
		);

		foreach ( $required_pages as $key => $page ) {
			$existing_page = get_page_by_path( $page['slug'] );

			if ( ! $existing_page ) {
				$page_id = wp_insert_post(
					array(
						'post_title'   => $page['title'],
						'post_name'    => $page['slug'],
						'post_content' => $page['content'],
						'post_status'  => 'publish',
						'post_type'    => 'page',
					)
				);

				if ( ! is_wp_error( $page_id ) ) {
					update_option( "_gigneo_ts_template_$key", $page_id );
				}
			} else {
				update_option( "_gigneo_ts_template_$key", $existing_page->ID );
			}
		}

		// Mark as completed to avoid repeating
		update_option( '_gigneo_required_pages_status', true );
	}

	/**
	 * Create required products for the plugin.
	 *
	 * This function creates the necessary products for the plugin if they do not already exist.
	 * It checks for existing products by their slug and creates them with default content if not found.
	 *
	 * @throws WC_Data_Exception
	 * @since 0.0.1
	 */
	private static function create_products() {
		if ( get_option( '_gigneo_required_products_status' ) ) {
			return;
		}

		$products = array(
			'wallet'     => array(
				'name'        => esc_html__( 'Wallet', 'gigneo' ),
				'slug'        => 'wallet',
				'price'       => 1,
				'description' => esc_html__( 'This is the product to add funds to wallet.', 'gigneo' ),
			),
			'withdrawal' => array(
				'name'        => esc_html__( 'Withdrawal', 'gigneo' ),
				'slug'        => 'withdrawal',
				'price'       => 1,
				'description' => esc_html__( 'This is the product to add withdrawal funds. Please do not delete.', 'gigneo' ),
			),
		);

		foreach ( $products as $key => $product ) {
			$existing = get_page_by_path( $product['slug'], OBJECT, 'product' );
			if ( ! $existing ) {
				$product_id = wp_insert_post(
					array(
						'post_title'   => $product['name'],
						'post_name'    => $product['slug'],
						'post_content' => $product['description'],
						'post_status'  => 'publish',
						'post_type'    => 'product',
					)
				);

				if ( ! is_wp_error( $product_id ) ) {

					update_post_meta( $product_id, '_price', $product['price'] );
					update_post_meta( $product_id, '_regular_price', $product['price'] );
					update_post_meta( $product_id, '_stock_status', 'instock' );
					update_post_meta( $product_id, '_virtual', 'yes' );
					update_post_meta( $product_id, '_downloadable', 'yes' );
					update_post_meta( $product_id, '_manage_stock', 'no' );
					update_post_meta( $product_id, '_sold_individually', 'yes' );
					wp_set_object_terms( $product_id, 'simple', 'product_type' );

					// Update theme option
					update_option( "_gigneo_ts_{$key}_product", $product_id );

					// Hide from catalog and search
					$wc_product = wc_get_product( $product_id );
					if ( $wc_product ) {
						$wc_product->set_catalog_visibility( 'hidden' );
						$wc_product->set_virtual( true );
						$wc_product->set_downloadable( true );
						$wc_product->save();
					}
				}
			} else {
				update_option( "_gigneo_ts_{$key}_product", $existing->ID );
			}
		}
		update_option( '_gigneo_required_products_status', true );
	}

	/**
	 * Create required tables for the plugin.
	 *
	 * This function creates the necessary tables for the plugin if they do not already exist.
	 * It uses the dbDelta function to create or update the table structure.
	 *
	 * @since 0.0.1
	 */
	public static function create_tables() {
		global $wpdb;
		// phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery
		$charset_collate = $wpdb->get_charset_collate();
		// phpcs:enable WordPress.DB.DirectDatabaseQuery.DirectQuery

		require_once ABSPATH . 'wp-admin/includes/upgrade.php';

		/**
		 * Create gigneo_notifications table
		 */

		// phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery
		$notification_table = $wpdb->prefix . 'gigneo_notifications';
		// phpcs:enable WordPress.DB.DirectDatabaseQuery.DirectQuery
		$sql_notification = "CREATE TABLE $notification_table (
		    id BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
		    profile_id BIGINT(20) UNSIGNED NOT NULL,
		    post_id BIGINT(20) UNSIGNED NULL,
		    title VARCHAR(255) NOT NULL,
		    content TEXT NOT NULL,
		    category VARCHAR(50) NOT NULL,
		    type VARCHAR(50) NOT NULL,
		    status VARCHAR(20) NOT NULL DEFAULT 'unread',
		    meta Varchar(255) NULL,
		    created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
		    created_at_gmt DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
		    updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
		    updated_at_gmt DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
		    PRIMARY KEY (id),
		    INDEX profile_id (profile_id),
		    INDEX post_id (post_id),
		    INDEX status (status),
		    KEY created_at (created_at),
		    KEY created_at_gmt (created_at_gmt)
		) $charset_collate;";

		dbDelta( $sql_notification );

		/**
		 * Create gigneo_messages table
		 */
		// phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery
		$table_messages = $wpdb->prefix . 'gigneo_messages';
		// phpcs:enable WordPress.DB.DirectDatabaseQuery.DirectQuery

		$sql_messages = "CREATE TABLE $table_messages (
	        id BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
	        post_id BIGINT(20) NULL,
	        sender_id BIGINT(20) NOT NULL,
	        receiver_id BIGINT(20) NOT NULL,
	        message LONGTEXT NOT NULL,
	        filter_message LONGTEXT NOT NULL,
	        attachments TEXT NULL DEFAULT NULL,
	        reply TEXT NULL DEFAULT NULL,
	        status VARCHAR(20) NOT NULL DEFAULT 'unread',
	        sent_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
		    sent_at_gmt DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
		    read_at DATETIME NULL DEFAULT NULL,
		    read_at_gmt DATETIME NULL DEFAULT NULL,
	        reaction VARCHAR(50) NOT NULL DEFAULT '',
	        pinned TINYINT(1) NOT NULL DEFAULT 0,
	        type VARCHAR(20) NOT NULL,
	        PRIMARY KEY (id),
	        KEY sender_id (sender_id),
	        KEY receiver_id (receiver_id),
	        KEY status (status),
	        KEY sent_at (sent_at),
	        KEY sent_at_gmt (sent_at_gmt)
    	) $charset_collate;";

		dbDelta( $sql_messages );

		/**
		 * Create gigneo_attachments table
		 */
		// phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery
		$table_attachments = $wpdb->prefix . 'gigneo_attachments';
		// phpcs:enable WordPress.DB.DirectDatabaseQuery.DirectQuery

		$sql_attachments = "CREATE TABLE $table_attachments (
	        id BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
	        profile_id BIGINT(20) UNSIGNED NOT NULL,
	        post_id BIGINT(20) UNSIGNED NULL,
	        name VARCHAR(255) NOT NULL,
	        size BIGINT(20) NOT NULL,
	        mime_type VARCHAR(100) NOT NULL,
	        guid VARCHAR(255) NOT NULL,
	        path VARCHAR(255) NOT NULL,
	        meta Varchar(255) NOT NULL,
	        post_type VARCHAR(100) NOT NULL,
	        uploaded_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
		    uploaded_at_gmt DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
	        PRIMARY KEY (id),
	        KEY post_id (post_id)
	    ) $charset_collate;";

		dbDelta( $sql_attachments );

		/**
		 * Create gigneo_chats table
		 */
		// phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery
		$table_memberlist = $wpdb->prefix . 'gigneo_chats';
		// phpcs:enable WordPress.DB.DirectDatabaseQuery.DirectQuery

		$sql_memberlist = "CREATE TABLE $table_memberlist (
	        id BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
	        profile_id BIGINT(20) UNSIGNED NOT NULL,
	        member_id BIGINT(20) UNSIGNED NOT NULL,
	        status VARCHAR(50) NOT NULL DEFAULT 'pending',
	        chat_type VARCHAR(20) NOT NULL DEFAULT 'chat',
	        blocked_by BIGINT(20) UNSIGNED NULL,
	        favourite_by VARCHAR(20) NOT NULL,
	        mute_by VARCHAR(20) NOT NULL,
	        created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
		    created_at_gmt DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
		    updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
		    updated_at_gmt DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
	        PRIMARY KEY (id),
	        KEY profile_id (profile_id),
	        KEY member_id (member_id)
    	) $charset_collate;";

		dbDelta( $sql_memberlist );
	}

	/**
	 * Deactivate the plugin.
	 *
	 * This function clears the scheduled cron event for cleaning old notifications.
	 *
	 * @since 0.0.1
	 */
	public static function plugin_deactivate() {
		if ( class_exists( Notifications::class ) && method_exists( Notifications::class, 'clear_clean_old_notifications_cron' ) ) {
			Notifications::clear_clean_old_notifications_cron();
		}
	}
}
