<?php

namespace RobotsTxtManager;

use WP_PowerSuite\Core\AbstractModule;
use WP_PowerSuite\Core\Contracts\DataLocationsInterface;
use WP_PowerSuite\Core\RootTextFileHelper;

class Module extends AbstractModule implements DataLocationsInterface {

	private const MODULE_ID = 'robots-txt-manager';
	private const MODULE_VERSION = '1.0.0';

	public function getId(): string {
		return self::MODULE_ID;
	}

	public function getName(): string {
		return __( 'Robots.txt Manager', 'wp-powersuite' );
	}

	public function getVersion(): string {
		return self::MODULE_VERSION;
	}

	public function getDescription(): string {
		return __( 'Manage robots.txt and crawler hints from the dashboard—no FTP.', 'wp-powersuite' );
	}

	public function getContext(): string|array {
		return [ 'admin', 'frontend' ];
	}

	protected function registerHooks(): void {
		add_filter( 'robots_txt', [ $this, 'filterRobotsTxt' ], 10, 2 );
	}

	/**
	 * {@inheritdoc}
	 */
	public function getDataLocations(): array {
		return [
			'option_store_keys' => [ self::MODULE_ID ],
		];
	}

	/**
	 * Filter robots.txt output when using option fallback (root not writable).
	 *
	 * @param string $output Default WordPress output.
	 * @param bool   $public Whether the site is public.
	 * @return string
	 */
	public function filterRobotsTxt( string $output, bool $public ): string {
		if ( $this->isWritable() ) {
			return $output;
		}
		$content = $this->getOptionContent();
		if ( $content !== '' ) {
			return $content;
		}
		return $output;
	}

	/**
	 * Get robots.txt content from option (fallback when not writable).
	 *
	 * @return string
	 */
	private function getOptionContent(): string {
		$settings = $this->moduleSettings()->all( [] );
		$content  = isset( $settings['content'] ) ? (string) $settings['content'] : '';
		return trim( $content );
	}

	/**
	 * Save content to option (fallback when not writable).
	 *
	 * @param string $content Raw content.
	 * @return bool
	 */
	private function saveOptionContent( string $content ): bool {
		return $this->moduleSettings()->save( [ 'content' => $content ] );
	}

	/**
	 * Get path to robots.txt.
	 *
	 * @return string
	 */
	public function getPath(): string {
		return RootTextFileHelper::getRootFilePath( 'robots.txt' );
	}

	/**
	 * Check if robots.txt exists.
	 *
	 * @return bool
	 */
	public function exists(): bool {
		return file_exists( $this->getPath() );
	}

	/**
	 * Check if robots.txt (or root) is writable.
	 *
	 * @return bool
	 */
	public function isWritable(): bool {
		return RootTextFileHelper::isWritable( $this->getPath() );
	}

	/**
	 * Get robots.txt content for the admin editor.
	 * Never uses HTTP — password protection and maintenance plugins block front-end URLs.
	 *
	 * @return string
	 */
	public function getContent(): string {
		$path = $this->getPath();

		if ( ! $this->isWritable() ) {
			$content = $this->getOptionContent();
			if ( $content !== '' ) {
				return $content;
			}
			return $this->getFilteredRobotsContent();
		}

		if ( file_exists( $path ) && is_readable( $path ) ) {
			$read = RootTextFileHelper::readFileContents( $path );
			if ( $read['success'] && trim( $read['content'] ) !== '' ) {
				return $read['content'];
			}
		}

		return $this->getFilteredRobotsContent();
	}

	/**
	 * Build the robots.txt WordPress would serve when no physical file exists.
	 */
	private function getFilteredRobotsContent(): string {
		$public = get_option( 'blog_public' );

		return apply_filters( 'robots_txt', $this->getDefaultContent(), (bool) $public );
	}

	/**
	 * Get WordPress default robots.txt content.
	 *
	 * @return string
	 */
	private function getDefaultContent(): string {
		$public = get_option( 'blog_public' );
		$output = '';
		if ( '0' === $public ) {
			$output .= "User-agent: *\n";
			$output .= "Disallow: /\n";
		} else {
			$output .= "User-agent: *\n";
			$output .= "Disallow: /wp-admin/\n";
			$output .= "Allow: /wp-admin/admin-ajax.php\n";
		}

		return $output;
	}

	/**
	 * Create backup of robots.txt in private storage.
	 *
	 * @return array{success: bool, message: string}
	 */
	public function createBackup(): array {
		$path = $this->getPath();
		if ( ! file_exists( $path ) || ! is_readable( $path ) ) {
			return [
				'success' => true,
				'message' => __( 'No file exists to backup.', 'wp-powersuite' ),
			];
		}

		$backup = RootTextFileHelper::createSecureBackup( $path, 'robots-txt' );
		if ( $backup === false ) {
			return [
				'success' => false,
				'message' => __( 'Could not create backup.', 'wp-powersuite' ),
			];
		}

		return [
			'success' => true,
			'message' => sprintf(
				/* translators: %s: backup filename */
				__( 'Backup created: %s', 'wp-powersuite' ),
				basename( (string) $backup )
			),
		];
	}

	/**
	 * Write content to robots.txt (file) or option (when not writable).
	 *
	 * @return array{success: bool, message: string}
	 */
	public function writeContent( string $content ): array {
		$size_error = RootTextFileHelper::validateContentSize( $content );
		if ( $size_error !== null ) {
			return [
				'success' => false,
				'message' => $size_error,
			];
		}

		$content = rtrim( $content ) . "\n";

		if ( $this->isWritable() ) {
			$path = $this->getPath();
			if ( file_exists( $path ) && is_readable( $path ) ) {
				RootTextFileHelper::createSecureBackup( $path, 'robots-txt' );
			}

			if ( ! RootTextFileHelper::atomicWrite( $path, $content ) ) {
				return [
					'success' => false,
					'message' => __( 'Could not write robots.txt.', 'wp-powersuite' ),
				];
			}

			return [
				'success' => true,
				'message' => __( 'Robots.txt saved.', 'wp-powersuite' ),
			];
		}

		if ( ! $this->saveOptionContent( $content ) ) {
			return [
				'success' => false,
				'message' => __( 'Could not save robots.txt settings.', 'wp-powersuite' ),
			];
		}

		return [
			'success' => true,
			'message' => __( 'Robots.txt saved.', 'wp-powersuite' ),
		];
	}

	/**
	 * Get default sitemap URL (WordPress core sitemap).
	 *
	 * @return string
	 */
	public function getSitemapUrl(): string {
		return home_url( '/wp-sitemap.xml' );
	}
}
