<?php
/**
 * Humanize Link API methods.
 *
 * Two-step flow: suggest → check → create.
 *
 * @package GoValid_QR
 */

defined( 'ABSPATH' ) || exit;

class GoValid_Link_API {

	/** @var GoValid_API_Client */
	private $client;

	/** @var GoValid_Cache */
	private $cache;

	public function __construct() {
		$this->client = new GoValid_API_Client();
		$this->cache  = GoValid_Cache::get_instance();
	}

	/**
	 * List user's humanize links.
	 *
	 * @param int    $page     Page number.
	 * @param int    $per_page Items per page.
	 * @param string $search   Search query.
	 * @return array|WP_Error
	 */
	public function list_links( int $page = 1, int $per_page = 20, string $search = '' ) {
		$cache_key = 'link_list_' . md5( $page . $per_page . $search );
		$cached    = $this->cache->get( $cache_key );
		if ( false !== $cached ) {
			return $cached;
		}

		$query = array(
			'page'     => $page,
			'per_page' => $per_page,
		);
		if ( ! empty( $search ) ) {
			$query['search'] = $search;
		}

		$result = $this->client->get( '/api/v1/links/', $query );
		if ( ! is_wp_error( $result ) ) {
			$this->cache->set( $cache_key, $result, 5 * MINUTE_IN_SECONDS );
		}

		return $result;
	}

	/**
	 * Get link detail.
	 *
	 * @param string $uuid Link UUID.
	 * @return array|WP_Error
	 */
	public function get_link_detail( string $uuid ) {
		$cache_key = 'link_detail_' . $uuid;
		$cached    = $this->cache->get( $cache_key );
		if ( false !== $cached ) {
			return $cached;
		}

		$result = $this->client->get( '/api/v1/links/' . rawurlencode( $uuid ) . '/' );
		if ( ! is_wp_error( $result ) ) {
			$this->cache->set( $cache_key, $result, 10 * MINUTE_IN_SECONDS );
		}

		return $result;
	}

	/**
	 * Step 1: Get AI-generated slug+domain suggestions.
	 *
	 * @param string $url         Target URL.
	 * @param string $title       Optional title for AI context.
	 * @param string $description Optional description for AI context.
	 * @param string $audience    'local', 'global', or 'both'.
	 * @return array|WP_Error  { suggestions: [...], remaining: int }
	 */
	public function suggest_link( string $url, string $title = '', string $description = '', string $audience = 'local' ) {
		$body = array( 'url' => $url );

		if ( ! empty( $title ) ) {
			$body['title'] = $title;
		}
		if ( ! empty( $description ) ) {
			$body['description'] = $description;
		}
		if ( ! empty( $audience ) ) {
			$body['audience'] = $audience;
		}

		return $this->client->post( '/api/v1/links/suggest/', $body );
	}

	/**
	 * Step 2: Check if a slug is available on a domain.
	 *
	 * @param string $slug   The slug to check.
	 * @param string $domain The domain to check on.
	 * @return array|WP_Error  { available: bool, reason?: string }
	 */
	public function check_slug( string $slug, string $domain ) {
		return $this->client->get( '/api/v1/links/check-slug/', array(
			'slug'   => $slug,
			'domain' => $domain,
		) );
	}

	/**
	 * Step 3: Create a link with explicit slug + domain.
	 *
	 * @param string $slug        The chosen slug.
	 * @param string $domain      The chosen domain.
	 * @param string $target_url  The URL to shorten.
	 * @param string $title       Optional title.
	 * @param string $ai_provider AI provider name (or 'manual').
	 * @return array|WP_Error
	 */
	public function create_link( string $slug, string $domain, string $target_url, string $title = '', string $ai_provider = 'manual' ) {
		$body = array(
			'slug'        => $slug,
			'domain'      => $domain,
			'target_url'  => $target_url,
			'ai_provider' => $ai_provider,
		);

		if ( ! empty( $title ) ) {
			$body['title'] = $title;
		}

		$result = $this->client->post( '/api/v1/links/create/', $body );

		// Flush list cache on successful creation.
		if ( ! is_wp_error( $result ) ) {
			$this->cache->flush_prefix( 'link_list_' );
		}

		return $result;
	}

	/**
	 * Update a link's target URL and/or title.
	 *
	 * @param string $uuid       Link UUID.
	 * @param string $target_url New target URL.
	 * @param string $title      New title (optional).
	 * @return array|WP_Error
	 */
	public function update_link( string $uuid, string $target_url, string $title = '' ) {
		$body = array( 'target_url' => $target_url );

		if ( '' !== $title ) {
			$body['title'] = $title;
		}

		$result = $this->client->post( '/api/v1/links/' . rawurlencode( $uuid ) . '/update/', $body );

		if ( ! is_wp_error( $result ) ) {
			$this->cache->flush_prefix( 'link_list_' );
			$this->cache->delete( 'link_detail_' . $uuid );
		}

		return $result;
	}

	/**
	 * Toggle link active/inactive.
	 *
	 * @param string $uuid Link UUID.
	 * @return array|WP_Error
	 */
	public function toggle_link( string $uuid ) {
		$result = $this->client->post( '/api/v1/links/' . rawurlencode( $uuid ) . '/toggle/' );

		if ( ! is_wp_error( $result ) ) {
			$this->cache->flush_prefix( 'link_list_' );
			$this->cache->delete( 'link_detail_' . $uuid );
		}

		return $result;
	}

	/**
	 * Delete a link.
	 *
	 * @param string $uuid Link UUID.
	 * @return array|WP_Error
	 */
	public function delete_link( string $uuid ) {
		$result = $this->client->delete( '/api/v1/links/' . rawurlencode( $uuid ) . '/delete/' );

		if ( ! is_wp_error( $result ) ) {
			$this->cache->flush_prefix( 'link_list_' );
			$this->cache->delete( 'link_detail_' . $uuid );
		}

		return $result;
	}

	/**
	 * Get link click statistics (last 30 days).
	 *
	 * @param string $uuid Link UUID.
	 * @return array|WP_Error
	 */
	public function get_link_stats( string $uuid ) {
		$cache_key = 'link_stats_' . $uuid;
		$cached    = $this->cache->get( $cache_key );
		if ( false !== $cached ) {
			return $cached;
		}

		$result = $this->client->get( '/api/v1/links/' . rawurlencode( $uuid ) . '/stats/' );
		if ( ! is_wp_error( $result ) ) {
			$this->cache->set( $cache_key, $result, 5 * MINUTE_IN_SECONDS );
		}

		return $result;
	}

	/* ===== Anonymous (unauthenticated) link endpoints ===== */

	/**
	 * Build anonymous endpoint URL.
	 *
	 * @param string $path  Relative path after /i/api/short-url/.
	 * @param array  $query Query parameters.
	 * @return string
	 */
	private function anon_url( string $path, array $query = array() ): string {
		$base = GoValid_QR::get_base_url();
		$url  = $base . '/i/api/short-url/' . ltrim( $path, '/' );
		if ( ! empty( $query ) ) {
			$url = add_query_arg( $query, $url );
		}
		return $url;
	}

	/**
	 * Make an unauthenticated JSON POST request.
	 *
	 * @param string $url  Full URL.
	 * @param array  $body Request body.
	 * @return array|WP_Error
	 */
	private function anon_post( string $url, array $body = array() ) {
		$response = wp_remote_post( $url, array(
			'timeout'    => 30,
			'headers'    => array(
				'Accept'       => 'application/json',
				'Content-Type' => 'application/json',
			),
			'body'       => wp_json_encode( $body ),
		) );

		return $this->parse_anon_response( $response );
	}

	/**
	 * Make an unauthenticated GET request.
	 *
	 * @param string $url Full URL.
	 * @return array|WP_Error
	 */
	private function anon_get( string $url ) {
		$response = wp_remote_get( $url, array(
			'timeout' => 30,
			'headers' => array(
				'Accept' => 'application/json',
			),
		) );

		return $this->parse_anon_response( $response );
	}

	/**
	 * Parse anonymous response.
	 *
	 * @param array|WP_Error $response
	 * @return array|WP_Error
	 */
	private function parse_anon_response( $response ) {
		if ( is_wp_error( $response ) ) {
			return $response;
		}

		$code = wp_remote_retrieve_response_code( $response );
		$body = wp_remote_retrieve_body( $response );
		$data = json_decode( $body, true );

		if ( $code >= 400 ) {
			$message = isset( $data['error'] )
				? $data['error']
				: __( 'API request failed.', 'govalid-qr' );
			return new WP_Error(
				'govalid_api_' . $code,
				$message,
				array( 'status' => $code )
			);
		}

		return is_array( $data ) ? $data : array();
	}

	/**
	 * Anonymous: Get AI-generated slug suggestions.
	 *
	 * @param string $url         Target URL.
	 * @param string $title       Optional title.
	 * @param string $description Optional description.
	 * @param string $audience    'local', 'global', or 'both'.
	 * @return array|WP_Error
	 */
	public function anon_suggest_link( string $url, string $title = '', string $description = '', string $audience = 'local' ) {
		$body = array( 'url' => $url );

		if ( ! empty( $title ) ) {
			$body['title'] = $title;
		}
		if ( ! empty( $description ) ) {
			$body['description'] = $description;
		}
		if ( ! empty( $audience ) ) {
			$body['audience'] = $audience;
		}

		return $this->anon_post( $this->anon_url( 'suggest/' ), $body );
	}

	/**
	 * Anonymous: Check if a slug is available.
	 *
	 * @param string $slug   The slug to check.
	 * @param string $domain The domain.
	 * @return array|WP_Error
	 */
	public function anon_check_slug( string $slug, string $domain ) {
		return $this->anon_get( $this->anon_url( 'check-slug/', array(
			'slug'   => $slug,
			'domain' => $domain,
		) ) );
	}

	/**
	 * Anonymous: Create a short URL.
	 *
	 * @param string $slug        The chosen slug.
	 * @param string $domain      The chosen domain.
	 * @param string $target_url  The URL to shorten.
	 * @param string $title       Optional title.
	 * @param string $ai_provider AI provider name.
	 * @return array|WP_Error
	 */
	public function anon_create_link( string $slug, string $domain, string $target_url, string $title = '', string $ai_provider = 'manual' ) {
		$body = array(
			'slug'        => $slug,
			'domain'      => $domain,
			'target_url'  => $target_url,
			'ai_provider' => $ai_provider,
		);

		if ( ! empty( $title ) ) {
			$body['title'] = $title;
		}

		$result = $this->anon_post( $this->anon_url( 'create/' ), $body );

		// Store link locally for display when not connected.
		if ( ! is_wp_error( $result ) ) {
			$this->store_anonymous_link( $result );
			$this->cache->flush_prefix( 'link_list_' );
		}

		return $result;
	}

	/**
	 * Store an anonymously created link in WP options.
	 *
	 * @param array $link_data Link data from API response.
	 */
	private function store_anonymous_link( array $link_data ): void {
		$links   = get_option( 'govalid_anonymous_links', array() );
		$links[] = array(
			'id'         => $link_data['id'] ?? '',
			'full_url'   => $link_data['full_url'] ?? '',
			'domain'     => $link_data['domain'] ?? '',
			'slug'       => $link_data['slug'] ?? '',
			'target_url' => $link_data['target_url'] ?? '',
			'created_at' => current_time( 'mysql' ),
			'is_active'  => true,
		);
		update_option( 'govalid_anonymous_links', $links );
	}

	/**
	 * Get locally stored anonymous links.
	 *
	 * @return array
	 */
	public function get_anonymous_links(): array {
		return get_option( 'govalid_anonymous_links', array() );
	}

	/**
	 * Count locally stored anonymous links.
	 *
	 * @return int
	 */
	public function count_anonymous_links(): int {
		return count( $this->get_anonymous_links() );
	}
}
