<?php

namespace rentsyst\includes\cli;

use Exception;
use rentsyst\admin\components\Rentsyst_Api;
use rentsyst\admin\components\Rentsyst_CatalogVehicles;
use rentsyst\includes\Rentsyst_PluginSettings;
use rentsyst\includes\RS_Company;
use WP_CLI;

/**
 * Rentsyst plugin CLI commands.
 *
 * ## EXAMPLES
 *
 *     # Authenticate with Rentsyst CRM
 *     $ wp rentsyst auth --client_id=xxx --client_secret=yyy
 *
 *     # Check connection status
 *     $ wp rentsyst status
 *
 *     # Sync vehicles from CRM
 *     $ wp rentsyst sync vehicles
 *
 *     # Sync company settings
 *     $ wp rentsyst sync settings
 *
 *     # Disconnect from CRM
 *     $ wp rentsyst disconnect
 */
class Rentsyst_CLI_Command
{
	const TIME_VEHICLE_SYNC = 'time_vehicle_sync';
	const TIME_SETTINGS_SYNC = 'time_settings_sync';

	/**
	 * Authenticate with Rentsyst CRM using client credentials.
	 *
	 * ## OPTIONS
	 *
	 * --client_id=<client_id>
	 * : The OAuth2 client ID from Rentsyst CRM.
	 *
	 * --client_secret=<client_secret>
	 * : The OAuth2 client secret from Rentsyst CRM.
	 *
	 * ## EXAMPLES
	 *
	 *     # Authenticate with credentials
	 *     $ wp rentsyst auth --client_id=your_client_id --client_secret=your_client_secret
	 *     Success: Successfully authenticated with Rentsyst CRM.
	 *
	 * @param array $args       Positional arguments.
	 * @param array $assoc_args Associative arguments.
	 */
	public function auth($args, $assoc_args)
	{
		$client_id = $assoc_args['client_id'] ?? null;
		$client_secret = $assoc_args['client_secret'] ?? null;

		if (empty($client_id) || empty($client_secret)) {
			WP_CLI::error('Both --client_id and --client_secret are required.');
			return;
		}

		$authInfo = (object) [
			'client_id' => $client_id,
			'client_secret' => $client_secret,
		];

		update_option('rentsyst_auth', $authInfo);

		Rentsyst_Api::refreshInstance();

		try {
			$api = Rentsyst_Api::getInstance();
			$token = $api->getToken();

			if (empty($token)) {
				delete_option('rentsyst_auth');
				WP_CLI::error('Authentication failed. Please check your credentials.');
				return;
			}

			$companySettings = $api->getCompanySettings();
			update_option(RS_Company::COMPANY_SETTINGS_ID, $companySettings);

			$date = current_time('mysql');
			update_option(self::TIME_SETTINGS_SYNC, $date);

			WP_CLI::success('Successfully authenticated with Rentsyst CRM.');
			WP_CLI::log(sprintf('Company settings synchronized at: %s', $date));
		} catch (Exception $e) {
			delete_option('rentsyst_auth');
			WP_CLI::error('Authentication failed: ' . $e->getMessage());
		}
	}

	/**
	 * Disconnect from Rentsyst CRM.
	 *
	 * ## EXAMPLES
	 *
	 *     # Disconnect from CRM
	 *     $ wp rentsyst disconnect
	 *     Success: Disconnected from Rentsyst CRM.
	 *
	 * @param array $args       Positional arguments.
	 * @param array $assoc_args Associative arguments.
	 */
	public function disconnect($args, $assoc_args)
	{
		$authInfo = get_option('rentsyst_auth');

		if (empty($authInfo)) {
			WP_CLI::warning('Not connected to Rentsyst CRM.');
			return;
		}

		delete_option('rentsyst_auth');
		delete_option(Rentsyst_Api::TOKEN_OPTIONS_NAME);

		WP_CLI::success('Disconnected from Rentsyst CRM.');
	}

	/**
	 * Show current connection status.
	 *
	 * ## OPTIONS
	 *
	 * [--format=<format>]
	 * : Output format.
	 * ---
	 * default: table
	 * options:
	 *   - table
	 *   - json
	 *   - yaml
	 * ---
	 *
	 * ## EXAMPLES
	 *
	 *     # Check connection status
	 *     $ wp rentsyst status
	 *
	 *     # Get status as JSON
	 *     $ wp rentsyst status --format=json
	 *
	 * @param array $args       Positional arguments.
	 * @param array $assoc_args Associative arguments.
	 */
	public function status($args, $assoc_args)
	{
		$format = $assoc_args['format'] ?? 'table';
		$authInfo = get_option('rentsyst_auth');

		$status = [
			'connected' => !empty($authInfo),
			'client_id' => $authInfo->client_id ?? 'N/A',
			'last_vehicle_sync' => get_option(self::TIME_VEHICLE_SYNC) ?: 'Never',
			'last_settings_sync' => get_option(self::TIME_SETTINGS_SYNC) ?: 'Never',
			'catalog_enabled' => Rentsyst_PluginSettings::isCatalogVehiclesEnable() ? 'Yes' : 'No',
		];

		if ($format === 'json') {
			WP_CLI::log(json_encode($status, JSON_PRETTY_PRINT));
		} elseif ($format === 'yaml') {
			foreach ($status as $key => $value) {
				if (is_bool($value)) {
					$value = $value ? 'true' : 'false';
				}
				WP_CLI::log("$key: $value");
			}
		} else {
			$items = [];
			foreach ($status as $key => $value) {
				if (is_bool($value)) {
					$value = $value ? 'Yes' : 'No';
				}
				$items[] = [
					'Property' => $key,
					'Value' => $value,
				];
			}
			WP_CLI\Utils\format_items('table', $items, ['Property', 'Value']);
		}
	}

	/**
	 * Synchronize data from Rentsyst CRM.
	 *
	 * ## OPTIONS
	 *
	 * <type>
	 * : Type of data to sync.
	 * ---
	 * options:
	 *   - vehicles
	 *   - settings
	 *   - images
	 *   - all
	 * ---
	 *
	 * [--with-images]
	 * : Also upload images after syncing vehicles (only for 'vehicles' type).
	 *
	 * ## EXAMPLES
	 *
	 *     # Sync all vehicles
	 *     $ wp rentsyst sync vehicles
	 *
	 *     # Sync vehicles with images
	 *     $ wp rentsyst sync vehicles --with-images
	 *
	 *     # Sync company settings
	 *     $ wp rentsyst sync settings
	 *
	 *     # Sync everything
	 *     $ wp rentsyst sync all
	 *
	 * @param array $args       Positional arguments.
	 * @param array $assoc_args Associative arguments.
	 */
	public function sync($args, $assoc_args)
	{
		$type = $args[0] ?? 'all';
		$withImages = isset($assoc_args['with-images']);

		$authInfo = get_option('rentsyst_auth');
		if (empty($authInfo)) {
			WP_CLI::error('Not connected to Rentsyst CRM. Please run "wp rentsyst auth" first.');
			return;
		}

		switch ($type) {
			case 'vehicles':
				$this->syncVehicles($withImages);
				break;
			case 'settings':
				$this->syncSettings();
				break;
			case 'images':
				$this->syncImages();
				break;
			case 'all':
				$this->syncSettings();
				$this->syncVehicles($withImages);
				break;
			default:
				WP_CLI::error("Unknown sync type: $type");
		}
	}

	/**
	 * Update vehicle booking parameters.
	 *
	 * ## OPTIONS
	 *
	 * <params>
	 * : JSON string with vehicle parameters.
	 *
	 * ## EXAMPLES
	 *
	 *     # Set vehicle parameters
	 *     $ wp rentsyst set-params '{"show_price":true,"show_deposit":false}'
	 *
	 * @param array $args       Positional arguments.
	 * @param array $assoc_args Associative arguments.
	 */
	public function set_params($args, $assoc_args)
	{
		$params = $args[0] ?? null;

		if (empty($params)) {
			WP_CLI::error('Parameters JSON string is required.');
			return;
		}

		$decoded = json_decode($params, true);
		if (json_last_error() !== JSON_ERROR_NONE) {
			WP_CLI::error('Invalid JSON: ' . json_last_error_msg());
			return;
		}

		update_option('rentsyst_booking_vehicle_params', $decoded);

		WP_CLI::success('Vehicle parameters updated successfully.');
	}

	/**
	 * Sync vehicles from CRM.
	 *
	 * @param bool $withImages Whether to also upload images.
	 */
	private function syncVehicles($withImages = false)
	{
		if (!Rentsyst_PluginSettings::isCatalogVehiclesEnable()) {
			WP_CLI::warning('Vehicle catalog is not enabled. Enable it in plugin settings first.');
			return;
		}

		WP_CLI::log('Syncing vehicles from Rentsyst CRM...');

		try {
			ini_set('max_execution_time', '1000');
			ini_set('memory_limit', '256M');

			$api = Rentsyst_Api::getInstance();
			$vehicles = $api->getAllVehicles();

			if (empty($vehicles)) {
				WP_CLI::warning('No vehicles found in CRM.');
				return;
			}

			$imagesForUpload = Rentsyst_CatalogVehicles::updateVehicles($vehicles);

			$date = current_time('mysql');
			update_option(self::TIME_VEHICLE_SYNC, $date);

			$vehicleCount = is_array($vehicles) ? count($vehicles) : 0;
			WP_CLI::success(sprintf('Synced %d vehicles at %s', $vehicleCount, $date));

			if (Rentsyst_CatalogVehicles::getLastSyncWarning() !== '') {
				WP_CLI::warning(Rentsyst_CatalogVehicles::getLastSyncWarning());
			}

			if ($withImages && !empty($imagesForUpload)) {
				$this->uploadImages($imagesForUpload);
			} elseif (!empty($imagesForUpload)) {
				WP_CLI::log(sprintf('%d images pending. Run "wp rentsyst sync images" or use --with-images flag.', count($imagesForUpload)));
			}
		} catch (Exception $e) {
			WP_CLI::error('Failed to sync vehicles: ' . $e->getMessage());
		}
	}

	/**
	 * Sync company settings from CRM.
	 */
	private function syncSettings()
	{
		WP_CLI::log('Syncing settings from Rentsyst CRM...');

		try {
			$api = Rentsyst_Api::getInstance();
			$companySettings = $api->getCompanySettings();

			update_option(RS_Company::COMPANY_SETTINGS_ID, $companySettings);

			$date = current_time('mysql');
			update_option(self::TIME_SETTINGS_SYNC, $date);

			WP_CLI::success(sprintf('Settings synchronized at %s', $date));
		} catch (Exception $e) {
			WP_CLI::error('Failed to sync settings: ' . $e->getMessage());
		}
	}

	/**
	 * Sync images for vehicles.
	 */
	private function syncImages()
	{
		WP_CLI::log('Uploading vehicle images...');

		$args = [
			'post_type' => 'rs_vehicle',
			'posts_per_page' => -1,
			'meta_query' => [
				[
					'key' => '_rentsyst_image_pending',
					'value' => '1',
					'compare' => '=',
				],
			],
		];

		$query = new \WP_Query($args);

		if (!$query->have_posts()) {
			WP_CLI::success('No pending images to upload.');
			return;
		}

		$progress = \WP_CLI\Utils\make_progress_bar('Uploading images', $query->found_posts);

		while ($query->have_posts()) {
			$query->the_post();
			$post_id = get_the_ID();

			try {
				Rentsyst_CatalogVehicles::uploadImage($post_id);
				delete_post_meta($post_id, '_rentsyst_image_pending');
			} catch (Exception $e) {
				WP_CLI::warning(sprintf('Failed to upload image for post %d: %s', $post_id, $e->getMessage()));
			}

			$progress->tick();
		}

		$progress->finish();
		wp_reset_postdata();

		WP_CLI::success('Image upload completed.');
	}

	/**
	 * Upload images for specific vehicle posts.
	 *
	 * @param array $imagesForUpload Array of post IDs.
	 */
	private function uploadImages($imagesForUpload)
	{
		if (empty($imagesForUpload)) {
			return;
		}

		$progress = \WP_CLI\Utils\make_progress_bar('Uploading images', count($imagesForUpload));

		foreach ($imagesForUpload as $post_id) {
			try {
				Rentsyst_CatalogVehicles::uploadImage($post_id);
			} catch (Exception $e) {
				WP_CLI::warning(sprintf('Failed to upload image for post %d: %s', $post_id, $e->getMessage()));
			}
			$progress->tick();
		}

		$progress->finish();
		WP_CLI::success('Image upload completed.');
	}
}
