<?php
/**
 * Structure Viewer — File Viewer
 *
 * AJAX handlers for viewing and downloading individual files.
 */

if ( ! defined( 'ABSPATH' ) ) {
    exit( 'Direct access denied.' );
}

final class SV_FileViewer {

    /** Maximum file size we'll read into memory for inline viewing (from settings). */
    private static function max_bytes() {
        $mb = absint( SV_Settings::get()['max_file_size'] ?? 1 );
        $mb = max( 1, min( 50, $mb ) );
        return $mb * 1048576;
    }

    /** AJAX: view a file in the modal. */
    public static function ajax_view_file() {
        check_ajax_referer( STRUCTUREVIEWER_NONCE, 'nonce' );

        if ( ! current_user_can( 'manage_options' ) ) {
            wp_send_json_error( [ 'message' => 'Permission denied.' ] );
        }

        $type      = isset( $_POST['type'] )      ? sanitize_text_field( wp_unslash( $_POST['type'] ) )             : '';
        $item      = isset( $_POST['item'] )      ? SV_Sanitizer::item_name( sanitize_text_field( wp_unslash( $_POST['item'] ) ) )         : '';
        $file_path = isset( $_POST['file_path'] ) ? sanitize_text_field( wp_unslash( $_POST['file_path'] ) )        : '';

        if ( ! in_array( $type, [ 'plugin', 'theme' ], true ) || ! $item || ! $file_path ) {
            wp_send_json_error( [ 'message' => 'Invalid parameters.' ] );
        }

        $resolved = self::resolve_path( $type, $item, $file_path );
        if ( is_wp_error( $resolved ) ) {
            wp_send_json_error( [ 'message' => $resolved->get_error_message() ] );
        }

        $size = filesize( $resolved );
        if ( $size > self::max_bytes() ) {
            wp_send_json_error( [
                'message' => sprintf(
                    /* translators: file size */
                    esc_html__( 'File too large to display (%s).', 'structure-viewer' ),
                    size_format( $size, 2 )
                )
            ] );
        }

        $content = file_get_contents( $resolved ); // phpcs:ignore WordPress.WP.AlternativeFunctions
        if ( $content === false ) {
            wp_send_json_error( [ 'message' => 'Could not read file.' ] );
        }

        wp_send_json_success( [
            'file_name' => basename( $resolved ),
            'content'   => $content,
            'size'      => size_format( $size, 2 ),
            'modified'  => gmdate( 'Y-m-d H:i', filemtime( $resolved ) ),
            'lines'     => substr_count( $content, "\n" ) + 1,
        ] );
    }

    /** AJAX: download a file as base64-encoded blob. */
    public static function ajax_download_file() {
        check_ajax_referer( STRUCTUREVIEWER_NONCE, 'nonce' );

        if ( ! current_user_can( 'manage_options' ) ) {
            wp_send_json_error( [ 'message' => 'Permission denied.' ] );
        }

        $type      = isset( $_POST['type'] )      ? sanitize_text_field( wp_unslash( $_POST['type'] ) )      : '';
        $item      = isset( $_POST['item'] )      ? SV_Sanitizer::item_name( sanitize_text_field( wp_unslash( $_POST['item'] ) ) ) : '';
        $file_path = isset( $_POST['file_path'] ) ? sanitize_text_field( wp_unslash( $_POST['file_path'] ) ) : '';

        if ( ! in_array( $type, [ 'plugin', 'theme' ], true ) || ! $item || ! $file_path ) {
            wp_send_json_error( [ 'message' => 'Invalid parameters.' ] );
        }

        $resolved = self::resolve_path( $type, $item, $file_path );
        if ( is_wp_error( $resolved ) ) {
            wp_send_json_error( [ 'message' => $resolved->get_error_message() ] );
        }

        $contents = file_get_contents( $resolved ); // phpcs:ignore WordPress.WP.AlternativeFunctions
        if ( $contents === false ) {
            wp_send_json_error( [ 'message' => 'Could not read file.' ] );
        }

        wp_send_json_success( [
            'filename'  => basename( $resolved ),
            'content'   => base64_encode( $contents ),
            'mime_type' => self::detect_mime( $resolved ),
            'size'      => size_format( filesize( $resolved ), 2 ),
        ] );
    }

    // ── Helpers ───────────────────────────────────────────────────────────────

    /**
     * Resolve and validate a file path relative to a plugin/theme directory.
     *
     * @return string|WP_Error  Absolute path on success, WP_Error on failure.
     */
    private static function resolve_path( $type, $item, $rel_path ) {
        $items_dir = ( $type === 'plugin' ) ? WP_PLUGIN_DIR : get_theme_root();
        $base      = realpath( $items_dir . '/' . $item );

        if ( ! $base || ! is_dir( $base ) ) {
            return new WP_Error( 'not_found', 'Item directory not found.' );
        }

        $full = realpath( $base . DIRECTORY_SEPARATOR . $rel_path );

        if ( ! $full || strpos( $full, $base . DIRECTORY_SEPARATOR ) !== 0 || ! is_file( $full ) ) {
            return new WP_Error( 'not_found', 'File not found or access denied.' );
        }

        return $full;
    }

    private static function detect_mime( $path ) {
        $mime = 'application/octet-stream';

        if ( function_exists( 'finfo_open' ) ) {
            $finfo    = finfo_open( FILEINFO_MIME_TYPE );
            $detected = $finfo ? finfo_file( $finfo, $path ) : false;
            if ( $finfo ) {
                finfo_close( $finfo );
            }
            if ( $detected ) {
                $mime = $detected;
            }
        }

        if ( $mime === 'application/octet-stream' ) {
            $map = [
                'php'  => 'application/x-httpd-php',
                'js'   => 'application/javascript',
                'css'  => 'text/css',
                'html' => 'text/html',
                'htm'  => 'text/html',
                'json' => 'application/json',
                'xml'  => 'application/xml',
                'txt'  => 'text/plain',
                'md'   => 'text/markdown',
                'sql'  => 'application/sql',
                'svg'  => 'image/svg+xml',
                'png'  => 'image/png',
                'jpg'  => 'image/jpeg',
                'jpeg' => 'image/jpeg',
                'gif'  => 'image/gif',
                'webp' => 'image/webp',
                'ico'  => 'image/x-icon',
            ];
            $ext  = strtolower( pathinfo( $path, PATHINFO_EXTENSION ) );
            $mime = $map[ $ext ] ?? $mime;
        }

        return $mime;
    }
}