<?php
/**
 * DESCRIPTION: Orchestrates the setup wizard's finalize step — creates pages
 * and seeds a sample event based on the chosen business persona.
 *
 * @package Nemtly_Booking
 */

namespace NemtlyBooking\Services;

use NemtlyBooking\Core\Event_Creator;

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

/**
 * Setup Service — finalize-time work for the onboarding wizard.
 *
 * Owns the persona → pages and persona → sample-event mappings. The wizard
 * frontend doesn't know what gets created; it just calls finalize() and
 * receives a summary of what was done.
 *
 * @since PBOOKING_SINCE
 */
class Setup_Service {

    /**
     * Page definitions keyed by an internal slug. Each defines the title,
     * shortcode used as the page body, and which personas need it.
     *
     * @since PBOOKING_SINCE
     *
     * @var array
     */
    private $page_definitions = [
        'my-bookings' => [
            'title'     => 'My Bookings',
            'shortcode' => 'nemtly_booking_dashboard',
            'personas'  => [ 'tutor', 'studio', 'professional', 'other' ],
        ],
    ];

    /**
     * Map a public "role" identifier (used by the Settings UI and REST API)
     * to the matching internal page_definitions slug and the settings key
     * where the resulting page ID is stored.
     *
     * Public so the REST controller can validate role values without
     * duplicating this mapping.
     *
     * @since PBOOKING_SINCE
     *
     * @var array
     */
    public static $role_map = [
        'dashboard' => [
			'slug'        => 'my-bookings',
			'setting_key' => 'dashboard_page_id',
		],
    ];

    /**
     * Sample event definitions per persona. event_date is computed at runtime
     * (next matching weekday), so it is omitted here.
     *
     * @since PBOOKING_SINCE
     *
     * @var array
     */
    private $sample_event_definitions = [
        'tutor'        => [
            'title'              => '30-min Discovery Call',
            'description'        => 'A free 30-minute introductory call to discuss your goals.',
            'event_type'         => 'one-on-one',
            'event_duration'     => 30,
            'event_time'         => '09:00',
            'price'              => 0,
            'max_attendees'      => 1,
            'recurrence_pattern' => 'weekly',
            'recurrence_count'   => 0,
        ],
        'studio'       => [
            'title'              => 'Morning Yoga',
            'description'        => 'Start your day with a 60-minute yoga session for all levels.',
            'event_type'         => 'group',
            'event_duration'     => 60,
            'event_time'         => '07:00',
            'price'              => 15,
            'max_attendees'      => 12,
            'recurrence_pattern' => 'weekly',
            'recurrence_count'   => 0,
        ],
        'professional' => [
            'title'              => 'Strategy Session',
            'description'        => 'A focused 60-minute session to work through your business challenges.',
            'event_type'         => 'one-on-one',
            'event_duration'     => 60,
            'event_time'         => '09:00',
            'price'              => 150,
            'max_attendees'      => 1,
            'recurrence_pattern' => 'weekly',
            'recurrence_count'   => 0,
        ],
        'other'        => [
            'title'              => 'Sample Booking',
            'description'        => 'A starter event so you can see how bookings work. Edit or delete me anytime.',
            'event_type'         => 'one-on-one',
            'event_duration'     => 30,
            'event_time'         => '09:00',
            'price'              => 0,
            'max_attendees'      => 1,
            'recurrence_pattern' => 'weekly',
            'recurrence_count'   => 0,
        ],
    ];

    /**
     * Run the finalize step — create pages, seed sample event, mark complete.
     *
     * Safe to call more than once: pages with matching titles are reused, and
     * the sample event is only created if no event with the same title exists.
     *
     * @since PBOOKING_SINCE
     *
     * @param string $persona One of: tutor, studio, professional, other.
     *
     * @return array Summary: [ 'pages' => array<slug, post_id>, 'sample_event_id' => int|null ].
     */
    public function finalize( $persona ) {
        $persona = $this->normalize_persona( $persona );

        $pages           = $this->create_pages_for_persona( $persona );
        $sample_event_id = $this->seed_sample_event( $persona );

        $this->persist_page_settings( $pages );

        if ( $sample_event_id ) {
            update_option( 'nemtly_booking_sample_event_id', $sample_event_id );
        }

        update_option( 'nemtly_booking_setup_completed', true );

        return [
            'pages'           => $pages,
            'sample_event_id' => $sample_event_id,
        ];
    }

    /**
     * Write the created page IDs into the unified settings option so the
     * Settings → Pages tab and other consumers can read them.
     *
     * @since PBOOKING_SINCE
     *
     * @param array $pages Map of internal slug => post_id.
     *
     * @return void
     */
    private function persist_page_settings( $pages ) {
        $slug_to_setting = [
            'my-bookings' => 'dashboard_page_id',
        ];

        $update = [];
        foreach ( $slug_to_setting as $slug => $setting_key ) {
            if ( ! empty( $pages[ $slug ] ) ) {
                $update[ $setting_key ] = (int) $pages[ $slug ];
            }
        }

        if ( ! empty( $update ) ) {
            $settings_service = new Settings_Service();
            $settings_service->update_settings( $update );
        }
    }

    /**
     * Create (or reuse) the page for a single role and write the resulting
     * post ID into the matching settings key.
     *
     * Used by the Settings → Pages tab's "Create a page for me" action so
     * admins who skipped the wizard (or deleted a page) can recover without
     * leaving the settings screen.
     *
     * Idempotent: if a published page with the role's canonical title already
     * exists, it is reused rather than duplicated.
     *
     * @since PBOOKING_SINCE
     *
     * @param string $role Page role. Currently only 'dashboard' is supported.
     *
     * @return array|\WP_Error On success: [ id, title, link, setting_key, created ].
     *                         On failure: WP_Error.
     */
    public function create_page_for_role( $role ) {
        if ( ! isset( self::$role_map[ $role ] ) ) {
            return new \WP_Error(
                'nemtly_invalid_page_role',
                __( 'Unknown page role.', 'nemtly-booking' ),
                [ 'status' => 400 ]
            );
        }

        $slug        = self::$role_map[ $role ]['slug'];
        $setting_key = self::$role_map[ $role ]['setting_key'];
        $definition  = $this->page_definitions[ $slug ];

        $existing_id = $this->find_existing_page( $definition['title'] );
        $created     = false;

        if ( $existing_id ) {
            $page_id = $existing_id;
        } else {
            $insert = wp_insert_post(
                [
                    'post_title'     => $definition['title'],
                    'post_content'   => '[' . $definition['shortcode'] . ']',
                    'post_status'    => 'publish',
                    'post_type'      => 'page',
                    'post_author'    => get_current_user_id(),
                    'comment_status' => 'closed',
                    'ping_status'    => 'closed',
                ],
                true
            );

            if ( is_wp_error( $insert ) ) {
                return $insert;
            }

            if ( ! $insert ) {
                return new \WP_Error(
                    'nemtly_page_create_failed',
                    __( 'Failed to create the page.', 'nemtly-booking' ),
                    [ 'status' => 500 ]
                );
            }

            $page_id = (int) $insert;
            $created = true;
        }

        $settings_service = new Settings_Service();
        $settings_service->update_settings( [ $setting_key => $page_id ] );

        return [
            'id'          => $page_id,
            'title'       => get_the_title( $page_id ),
            'link'        => get_permalink( $page_id ),
            'setting_key' => $setting_key,
            'created'     => $created,
        ];
    }

    /**
     * Create (or reuse) the pages this persona needs.
     *
     * @since PBOOKING_SINCE
     *
     * @param string $persona Normalized persona key.
     *
     * @return array Map of page_slug => post_id.
     */
    private function create_pages_for_persona( $persona ) {
        $created = [];

        foreach ( $this->page_definitions as $slug => $definition ) {
            if ( ! in_array( $persona, $definition['personas'], true ) ) {
                continue;
            }

            $existing = $this->find_existing_page( $definition['title'] );
            if ( $existing ) {
                $created[ $slug ] = $existing;
                continue;
            }

            $post_id = wp_insert_post(
                [
                    'post_title'     => $definition['title'],
                    'post_content'   => '[' . $definition['shortcode'] . ']',
                    'post_status'    => 'publish',
                    'post_type'      => 'page',
                    'post_author'    => get_current_user_id(),
                    'comment_status' => 'closed',
                    'ping_status'    => 'closed',
                ],
                true
            );

            if ( ! is_wp_error( $post_id ) && $post_id ) {
                $created[ $slug ] = (int) $post_id;
            }
        }

        return $created;
    }

    /**
     * Find an existing published page by exact title.
     *
     * @since PBOOKING_SINCE
     *
     * @param string $title Page title.
     *
     * @return int|null Post ID or null.
     */
    private function find_existing_page( $title ) {
        $query = new \WP_Query(
            [
                'post_type'      => 'page',
                'title'          => $title,
                'posts_per_page' => 1,
                'no_found_rows'  => true,
                'fields'         => 'ids',
            ]
        );
        return $query->have_posts() ? (int) $query->posts[0] : null;
    }

    /**
     * Seed one sample event for this persona. Skipped if an event with the
     * same title already exists.
     *
     * @since PBOOKING_SINCE
     *
     * @param string $persona Normalized persona key.
     *
     * @return int|null Created post ID, or null on skip/failure.
     */
    private function seed_sample_event( $persona ) {
        if ( ! isset( $this->sample_event_definitions[ $persona ] ) ) {
            return null;
        }

        $definition = $this->sample_event_definitions[ $persona ];

        // Skip if a matching event already exists.
        $existing_query = new \WP_Query(
            [
                'post_type'      => 'nemtly_event',
                'title'          => $definition['title'],
                'posts_per_page' => 1,
                'no_found_rows'  => true,
                'fields'         => 'ids',
            ]
        );
        if ( $existing_query->have_posts() ) {
            return (int) $existing_query->posts[0];
        }

        $tomorrow = $this->next_weekday_iso();

        $creator = new Event_Creator();
        $result  = $creator->create_event(
            array_merge(
                $definition,
                [
                    'event_date'   => $tomorrow,
                    'timezone'     => wp_timezone_string(),
                    'is_recurring' => true,
                    'post_status'  => 'publish',
                ]
            )
        );

        if ( is_wp_error( $result ) ) {
            return null;
        }

        return (int) $result;
    }

    /**
     * ISO date for the next weekday (Mon–Fri). If today is a weekday and
     * before 23:00, returns tomorrow; if Friday/weekend, returns next Monday.
     *
     * @since PBOOKING_SINCE
     *
     * @return string Y-m-d.
     */
    private function next_weekday_iso() {
        $tz      = wp_timezone();
        $now     = new \DateTimeImmutable( 'now', $tz );
        $next    = $now->modify( '+1 day' );
        $weekday = (int) $next->format( 'N' ); // 1 (Mon) - 7 (Sun)

        if ( $weekday >= 6 ) {
            $next = $next->modify( 'next monday' );
        }

        return $next->format( 'Y-m-d' );
    }

    /**
     * Normalize an incoming persona string to one of the known keys.
     *
     * @since PBOOKING_SINCE
     *
     * @param string $persona Raw persona value.
     *
     * @return string Normalized key.
     */
    private function normalize_persona( $persona ) {
        $allowed = [ 'tutor', 'studio', 'professional', 'other' ];
        $persona = is_string( $persona ) ? strtolower( trim( $persona ) ) : '';

        return in_array( $persona, $allowed, true ) ? $persona : 'other';
    }
}
