<?php
/**
 * SocialPromoter Accounts
 *
 * Manages connected social media accounts. App credentials (App ID, App Secret)
 * and OAuth tokens are stored encrypted in wp_options.
 *
 * @package PublisherKits_SocialPromoter
 */

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

/**
 * Class PKITS_SP_Accounts
 */
class PKITS_SP_Accounts {

	/**
	 * wp_options key for connected accounts.
	 *
	 * @var string
	 */
	const ACCOUNTS_KEY = 'pkits_sp_accounts';

	/**
	 * wp_options key for app credentials.
	 *
	 * @var string
	 */
	const CREDS_KEY = 'pkits_sp_app_credentials';

	/**
	 * Valid platforms.
	 *
	 * @var string[]
	 */
	const PLATFORMS = array( 'x', 'facebook', 'linkedin', 'bluesky' );

	/**
	 * Get all connected accounts.
	 *
	 * @return array
	 */
	public static function get_all() {
		$raw = get_option( self::ACCOUNTS_KEY, array() );
		if ( ! is_array( $raw ) ) {
			return array();
		}
		$accounts = array();
		foreach ( $raw as $id => $account ) {
			$accounts[ $id ] = self::decrypt_account( $account );
		}
		return $accounts;
	}

	/**
	 * Get connected accounts for a specific platform.
	 *
	 * @param string $platform One of: x, facebook, linkedin.
	 * @return array
	 */
	public static function get_by_platform( $platform ) {
		$all = self::get_all();
		return array_filter(
			$all,
			function ( $account ) use ( $platform ) {
				return isset( $account['platform'] ) && $account['platform'] === $platform;
			}
		);
	}

	/**
	 * Whether an account is active for posting.
	 *
	 * Defaults to true when the flag is absent, so accounts connected before
	 * this feature existed remain available.
	 *
	 * @param array $account Account data.
	 * @return bool
	 */
	public static function is_active( array $account ) {
		return ! isset( $account['active'] ) || ! empty( $account['active'] );
	}

	/**
	 * Get all accounts that are active for posting.
	 *
	 * @return array
	 */
	public static function get_active() {
		return array_filter( self::get_all(), array( __CLASS__, 'is_active' ) );
	}

	/**
	 * Get active accounts for a specific platform.
	 *
	 * @param string $platform One of: x, facebook, linkedin.
	 * @return array
	 */
	public static function get_active_by_platform( $platform ) {
		return array_filter(
			self::get_by_platform( $platform ),
			array( __CLASS__, 'is_active' )
		);
	}

	/**
	 * Set the active-for-posting flag on a stored account.
	 *
	 * @param string $storage_id Storage key (platform_accountid).
	 * @param bool   $active     Whether the account should be active.
	 * @return bool True if the account exists and was updated.
	 */
	public static function set_active( $storage_id, $active ) {
		$raw = get_option( self::ACCOUNTS_KEY, array() );
		if ( ! is_array( $raw ) || ! isset( $raw[ $storage_id ] ) ) {
			return false;
		}
		// Stored record keeps token fields encrypted; only flip the plain flag.
		$raw[ $storage_id ]['active'] = $active ? 1 : 0;
		update_option( self::ACCOUNTS_KEY, $raw, false );
		return true;
	}

	/**
	 * Get a single account by ID.
	 *
	 * @param string $account_id Account identifier.
	 * @return array|null
	 */
	public static function get( $account_id ) {
		$all = self::get_all();
		return isset( $all[ $account_id ] ) ? $all[ $account_id ] : null;
	}

	/**
	 * Save a connected account.
	 *
	 * @param array $account Account data. Must include 'platform' and 'account_id'.
	 * @return bool
	 */
	public static function save( array $account ) {
		if ( empty( $account['platform'] ) || empty( $account['account_id'] ) ) {
			return false;
		}

		$raw = get_option( self::ACCOUNTS_KEY, array() );
		if ( ! is_array( $raw ) ) {
			$raw = array();
		}

		$id        = sanitize_key( $account['platform'] . '_' . $account['account_id'] );
		$encrypted = self::encrypt_account( $account );
		$raw[ $id ] = $encrypted;

		update_option( self::ACCOUNTS_KEY, $raw, false );
		return true;
	}

	/**
	 * Delete a connected account.
	 *
	 * @param string $storage_id The storage key (platform_accountid).
	 * @return bool
	 */
	public static function delete( $storage_id ) {
		$raw = get_option( self::ACCOUNTS_KEY, array() );
		if ( ! is_array( $raw ) || ! isset( $raw[ $storage_id ] ) ) {
			return false;
		}
		unset( $raw[ $storage_id ] );
		update_option( self::ACCOUNTS_KEY, $raw, false );
		return true;
	}

	/**
	 * Get app credentials for a platform.
	 *
	 * @param string $platform Platform slug.
	 * @return array Associative array of credentials (decrypted).
	 */
	public static function get_app_credentials( $platform ) {
		$all = get_option( self::CREDS_KEY, array() );
		if ( ! isset( $all[ $platform ] ) || ! is_array( $all[ $platform ] ) ) {
			return array();
		}
		$creds = $all[ $platform ];
		foreach ( $creds as $key => $value ) {
			$creds[ $key ] = PKITS_SP_Crypto::decrypt( $value );
		}
		return $creds;
	}

	/**
	 * Save app credentials for a platform.
	 *
	 * @param string $platform Platform slug.
	 * @param array  $creds    Credential key => value pairs.
	 * @return void
	 */
	public static function save_app_credentials( $platform, array $creds ) {
		$all = get_option( self::CREDS_KEY, array() );
		if ( ! is_array( $all ) ) {
			$all = array();
		}
		$encrypted = array();
		foreach ( $creds as $key => $value ) {
			$encrypted[ sanitize_key( $key ) ] = PKITS_SP_Crypto::encrypt( sanitize_text_field( $value ) );
		}
		$all[ sanitize_key( $platform ) ] = $encrypted;
		update_option( self::CREDS_KEY, $all, false );
	}

	/**
	 * Check whether app credentials are configured for a platform.
	 *
	 * @param string $platform Platform slug.
	 * @return bool
	 */
	public static function has_app_credentials( $platform ) {
		$creds = self::get_app_credentials( $platform );
		return ! empty( $creds );
	}

	/**
	 * Encrypt sensitive fields in an account array.
	 *
	 * @param array $account Raw account data.
	 * @return array Account with sensitive fields encrypted.
	 */
	private static function encrypt_account( array $account ) {
		$sensitive = array(
			'access_token',
			'access_token_secret',
			'refresh_token',
			'consumer_key',
			'consumer_secret',
			'app_secret',
			'app_password',
		);
		foreach ( $sensitive as $field ) {
			if ( isset( $account[ $field ] ) ) {
				$account[ $field ] = PKITS_SP_Crypto::encrypt( $account[ $field ] );
			}
		}
		return $account;
	}

	/**
	 * Decrypt sensitive fields in a stored account array.
	 *
	 * @param array $account Stored account data.
	 * @return array Account with sensitive fields decrypted.
	 */
	private static function decrypt_account( array $account ) {
		$sensitive = array(
			'access_token',
			'access_token_secret',
			'refresh_token',
			'consumer_key',
			'consumer_secret',
			'app_secret',
			'app_password',
		);
		foreach ( $sensitive as $field ) {
			if ( isset( $account[ $field ] ) ) {
				$account[ $field ] = PKITS_SP_Crypto::decrypt( $account[ $field ] );
			}
		}
		return $account;
	}
}
