<?php

/**
 * AP Family Archive - Import / Export tab (admin).
 *
 * GEDCOM import and basic export over the shared core GEDCOM services (both
 * free core capabilities) - the same engine AP Family Trees uses, so a file
 * imported here publishes identically in both plugins. Uploaded GEDCOM files
 * contain living-person PII, so uploads land in a protected, non-web-accessible
 * directory and are deleted after import (the Trees convention).
 *
 * @package    APFAAR_Family_Archive
 * @subpackage APFAAR_Family_Archive/admin
 * @since      0.1.0
 */
if ( !defined( 'ABSPATH' ) ) {
    exit;
}
/**
 * Import / Export tab.
 *
 * @since 0.1.0
 */
class APFAAR_Admin_Data {
    /**
     * Render the tab: import form + per-tree export/delete table.
     *
     * @return void
     */
    public static function render() {
        // ── Import ────────────────────────────────────────────────────────────
        echo '<div class="apfa-section-card">';
        echo '<h2 class="apfa-options-section-title">' . esc_html__( 'Import a GEDCOM', 'ap-family-archive' ) . '</h2>';
        echo '<p class="description">' . esc_html__( 'Upload a .ged file (GEDCOM 5.5 / 5.5.1) exported from any genealogy program. Each import creates a NEW tree - it never merges into or overwrites an existing one. After importing, choose the tree on the Dashboard tab to publish it.', 'ap-family-archive' ) . '</p>';
        echo '<form method="post" action="' . esc_url( admin_url( 'admin-post.php' ) ) . '" enctype="multipart/form-data">';
        wp_nonce_field( 'apfaar_import' );
        echo '<input type="hidden" name="action" value="apfaar_import" />';
        echo '<div class="apfa-field-group"><label class="apfa-field-label">' . esc_html__( 'GEDCOM file', 'ap-family-archive' ) . '</label>';
        echo '<input class="apfa-file-input" type="file" name="gedcom_file" accept=".ged,.gedcom" required /></div>';
        echo '<div class="apfa-field-group"><label class="apfa-field-label">' . esc_html__( 'Tree name', 'ap-family-archive' ) . '</label>';
        echo '<input class="apfa-field-input" type="text" name="tree_name" required placeholder="' . esc_attr__( 'e.g. Gray family', 'ap-family-archive' ) . '" />';
        echo '<p class="apfa-field-desc">' . esc_html__( 'A short identifier is generated from this name; the original file is deleted after import.', 'ap-family-archive' ) . '</p></div>';
        submit_button( __( 'Import', 'ap-family-archive' ) );
        echo '</form></div>';
        // ── Trees: export ─────────────────────────────────────────────────────
        echo '<div class="apfa-section-card">';
        echo '<h2 class="apfa-options-section-title">' . esc_html__( 'Export', 'ap-family-archive' ) . '</h2>';
        $trees = ( class_exists( 'AncestorPress\\Core\\Trees_Table' ) ? \AncestorPress\Core\Trees_Table::get_all() : array() );
        if ( empty( $trees ) ) {
            echo '<p class="description">' . esc_html__( 'No trees in the data core yet.', 'ap-family-archive' ) . '</p></div>';
            return;
        }
        echo '<p class="description">' . esc_html__( 'Download any tree as a complete GEDCOM 5.5.1 file, ready for any genealogy program - your data is never locked in. The export includes living people; treat the file accordingly.', 'ap-family-archive' ) . '</p>';
        echo '<table class="widefat striped"><thead><tr>' . '<th>' . esc_html__( 'Tree', 'ap-family-archive' ) . '</th>' . '<th>' . esc_html__( 'People', 'ap-family-archive' ) . '</th>' . '<th>' . esc_html__( 'Families', 'ap-family-archive' ) . '</th>' . '<th>' . esc_html__( 'Actions', 'ap-family-archive' ) . '</th>' . '</tr></thead><tbody>';
        foreach ( $trees as $tree ) {
            $export_url = wp_nonce_url( admin_url( 'admin-post.php?action=apfaar_export&tree=' . rawurlencode( $tree->gedcom ) ), 'apfaar_export_' . $tree->gedcom );
            $label = ( '' !== (string) $tree->treename ? $tree->treename : $tree->gedcom );
            // Basic GEDCOM export is a free core service - every user can take out
            // their own data.
            echo '<tr><td>' . esc_html( $label ) . ' <span class="apfa-gedcom-ref">' . esc_html( $tree->gedcom ) . '</span></td>' . '<td>' . esc_html( number_format_i18n( \AncestorPress\Core\People_Table::count_by_tree( $tree->gedcom ) ) ) . '</td>' . '<td>' . esc_html( number_format_i18n( \AncestorPress\Core\Families_Table::count_by_tree( $tree->gedcom ) ) ) . '</td>' . '<td><a class="button button-secondary" href="' . esc_url( $export_url ) . '">' . esc_html__( 'Download GEDCOM', 'ap-family-archive' ) . '</a></td></tr>';
        }
        echo '</tbody></table></div>';
    }

    // ── Handlers (called from APFAAR_Admin admin-post endpoints) ────────────────
    /**
     * Handle the GEDCOM upload + import. Returns a result for the notice.
     *
     * @return array { ok: bool, message: string }
     */
    public static function import() {
        // phpcs:disable WordPress.Security.NonceVerification.Missing -- caller (APFAAR_Admin) verified cap + nonce.
        if ( empty( $_FILES['gedcom_file'] ) || empty( $_FILES['gedcom_file']['tmp_name'] ) ) {
            return array(
                'ok'      => false,
                'message' => __( 'No file was uploaded.', 'ap-family-archive' ),
            );
        }
        $uploaded_tmp = $_FILES['gedcom_file']['tmp_name'];
        // phpcs:ignore WordPress.Security.ValidatedSanitizedInput -- path used only via is_uploaded_file + wp_handle_upload.
        $uploaded_name = ( isset( $_FILES['gedcom_file']['name'] ) ? sanitize_file_name( wp_unslash( $_FILES['gedcom_file']['name'] ) ) : 'upload.ged' );
        $ext = strtolower( pathinfo( $uploaded_name, PATHINFO_EXTENSION ) );
        if ( !in_array( $ext, array('ged', 'gedcom'), true ) ) {
            return array(
                'ok'      => false,
                'message' => __( 'Please upload a GEDCOM file (.ged or .gedcom).', 'ap-family-archive' ),
            );
        }
        if ( !is_uploaded_file( $uploaded_tmp ) ) {
            return array(
                'ok'      => false,
                'message' => __( 'Invalid file upload.', 'ap-family-archive' ),
            );
        }
        // Move the upload into a protected, non-web-accessible import directory
        // (GEDCOM files contain living-person PII and must not be downloadable).
        if ( !function_exists( 'wp_handle_upload' ) ) {
            require_once ABSPATH . 'wp-admin/includes/file.php';
        }
        self::prepare_import_dir();
        $dir_filter = static function ( $dirs ) {
            $sub = '/apfa-imports';
            $dirs['subdir'] = $sub;
            $dirs['path'] = $dirs['basedir'] . $sub;
            $dirs['url'] = $dirs['baseurl'] . $sub;
            return $dirs;
        };
        $overrides = array(
            'test_form'                => false,
            'test_upload'              => true,
            'mimes'                    => array(
                'ged'    => 'text/plain',
                'gedcom' => 'text/plain',
            ),
            'unique_filename_callback' => static function () {
                return 'apfa-gedcom-' . wp_generate_password( 12, false ) . '.ged';
            },
        );
        add_filter( 'upload_dir', $dir_filter );
        $uploaded = wp_handle_upload( $_FILES['gedcom_file'], $overrides );
        // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- wp_handle_upload sanitises internally.
        remove_filter( 'upload_dir', $dir_filter );
        if ( isset( $uploaded['error'] ) || !isset( $uploaded['file'] ) ) {
            return array(
                'ok'      => false,
                'message' => ( isset( $uploaded['error'] ) ? sanitize_text_field( $uploaded['error'] ) : __( 'Upload failed.', 'ap-family-archive' ) ),
            );
        }
        $tree_name = ( isset( $_POST['tree_name'] ) ? sanitize_text_field( wp_unslash( $_POST['tree_name'] ) ) : '' );
        // phpcs:enable
        $result = \AncestorPress\Core\Gedcom_Importer::run(
            $uploaded['file'],
            $tree_name,
            '',
            $uploaded_name
        );
        // Delete the temporary file whatever happened.
        wp_delete_file( $uploaded['file'] );
        if ( !empty( $result['errors'] ) ) {
            return array(
                'ok'      => false,
                'message' => implode( ' ', array_map( 'sanitize_text_field', $result['errors'] ) ),
            );
        }
        return array(
            'ok'      => true,
            'message' => sprintf(
                /* translators: 1: people count, 2: families count, 3: tree identifier. */
                __( 'Import complete: %1$d people and %2$d families imported as tree "%3$s". Select it on the Dashboard tab to publish it.', 'ap-family-archive' ),
                (int) $result['people'],
                (int) $result['families'],
                $result['gedcom']
            ),
        );
    }

    /**
     * Stream a tree as a GEDCOM download. Exits on success.
     *
     * @param  string $gedcom Tree identifier.
     * @return string|null    Error message when export failed (else exits).
     */
    public static function export( $gedcom ) {
        // Basic GEDCOM export is a free core service; the exporter is loaded on
        // boot by the shared core, the same way the importer is.
        $content = \AncestorPress\Core\Gedcom_Exporter::export( $gedcom );
        if ( is_wp_error( $content ) ) {
            return $content->get_error_message();
        }
        $filename = 'family-archive-' . sanitize_file_name( $gedcom ) . '-' . gmdate( 'Y-m-d' ) . '.ged';
        nocache_headers();
        header( 'Content-Type: text/plain; charset=UTF-8' );
        header( 'Content-Disposition: attachment; filename="' . $filename . '"' );
        header( 'Content-Length: ' . strlen( $content ) );
        // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- raw GEDCOM file download, not HTML.
        echo $content;
        exit;
    }

    /**
     * Ensure the protected import directory exists with deny files.
     *
     * @return void
     */
    private static function prepare_import_dir() {
        $uploads = wp_upload_dir();
        $dir = $uploads['basedir'] . '/apfa-imports';
        if ( !is_dir( $dir ) ) {
            wp_mkdir_p( $dir );
        }
        // Belt and braces: block web access and directory listing.
        if ( !file_exists( $dir . '/.htaccess' ) ) {
            @file_put_contents( $dir . '/.htaccess', "Deny from all\n" );
            // phpcs:ignore WordPress.PHP.NoSilencedErrors.Discouraged, WordPress.WP.AlternativeFunctions.file_system_operations_file_put_contents -- one-line guard file at dir creation.
        }
        if ( !file_exists( $dir . '/index.php' ) ) {
            @file_put_contents( $dir . '/index.php', "<?php\n// Silence is golden.\n" );
            // phpcs:ignore WordPress.PHP.NoSilencedErrors.Discouraged, WordPress.WP.AlternativeFunctions.file_system_operations_file_put_contents -- one-line guard file at dir creation.
        }
    }

}
