<?php

namespace Sikshya\Services\Frontend;

use Sikshya\Constants\PostTypes;
use Sikshya\Database\Repositories\ProgressRepository;
use Sikshya\Services\AssignmentService;
use Sikshya\Services\CourseService;
use Sikshya\Frontend\Site\CurriculumOutlineMeta;
use Sikshya\Frontend\Site\PublicPageUrls;
use Sikshya\Presentation\Models\SingleLessonPageModel;
use Sikshya\Services\LessonCourseLink;
use Sikshya\Services\PublicCurriculumService;
use Sikshya\Services\Settings;

/**
 * Builds the single-lesson shell view model for enrolled / preview learners.
 *
 * @package Sikshya\Services\Frontend
 */
final class LessonPageService
{
    public static function forPost(\WP_Post $post): SingleLessonPageModel
    {
        $lesson_id = (int) $post->ID;
        $course_id = self::lessonCourseId($post);
        $uid       = get_current_user_id();

        $error    = '';
        $enrolled = false;
        $blocks   = [];
        $is_preview = false;

        $track_progress = Settings::isTruthy(Settings::get('track_lesson_progress', true));
        $show_progress = Settings::isTruthy(Settings::get('students_can_see_progress', true));

        if ($course_id <= 0) {
            $error = $post->post_type === PostTypes::ASSIGNMENT
                ? __('This assignment is not linked to a course.', 'sikshya')
                : __('This lesson is not linked to a course.', 'sikshya');
        } else {
            $courses  = new CourseService();
            $enrolled = $uid > 0 && $courses->isUserEnrolled($uid, $course_id);

            $raw = PublicCurriculumService::getCourseCurriculum($course_id);

            // Allow preview when enabled globally and for the course.
            if (!$enrolled) {
                $is_preview = self::canPreviewContent($course_id, $raw, $lesson_id);
            }

            // Always show curriculum for non-enrolled visitors (locks on paid items); main body uses $error/$is_preview.
            $outline_preview_mode = !$enrolled;

            if (!$enrolled && !$is_preview) {
                $error = $uid <= 0
                    ? __('Please log in to access this lesson.', 'sikshya')
                    : __('You are not enrolled in this course.', 'sikshya');
            } elseif ($error === '' && $enrolled && !$is_preview) {
                $access_type = $post->post_type === PostTypes::ASSIGNMENT ? 'assignment' : 'lesson';
                $access = apply_filters(
                    'sikshya_access_check',
                    ['ok' => true, 'message' => ''],
                    [
                        'type' => $access_type,
                        'user_id' => $uid,
                        'course_id' => $course_id,
                        'content_id' => $lesson_id,
                    ]
                );
                if (is_array($access) && isset($access['ok']) && $access['ok'] === false) {
                    $msg = isset($access['message']) ? (string) $access['message'] : '';
                    $error = $msg !== '' ? $msg : __('This content is not available yet.', 'sikshya');
                }
            }

            $blocks = self::enrichBlocks(
                $uid,
                $course_id,
                $raw,
                $lesson_id,
                $track_progress && $show_progress,
                $enrolled,
                $outline_preview_mode
            );
        }

        $course_post = $course_id > 0 ? get_post($course_id) : null;
        $stats       = ($track_progress && $show_progress) ? self::computeStats($blocks) : ['total_items' => 0, 'completed_items' => 0, 'percent' => 0];
        $nav         = self::computePrevNext($blocks, $lesson_id);
        $current_chapter = self::currentChapterFor($blocks);
        $current_completed = self::isCurrentCompleted($blocks);

        $course_features = self::courseFeatures($course_id);

        $lesson_type = sanitize_key((string) get_post_meta($lesson_id, '_sikshya_lesson_type', true));

        $assignment_learn = self::buildAssignmentLearnPayload($post, $course_id, $uid, $enrolled, $is_preview);

        $vm = apply_filters(
            'sikshya_lesson_template_data',
            [
                'post' => $post,
                'lesson_id' => $lesson_id,
                'course_id' => $course_id,
                'course' => $course_post,
                'current_chapter' => $current_chapter,
                'logged_in' => $uid > 0,
                'enrolled' => $enrolled,
                'is_preview' => $is_preview,
                'error' => $error,
                'blocks' => $blocks,
                'stats' => $stats,
                'nav' => $nav,
                'show_progress' => $track_progress && $show_progress,
                'current_completed' => $current_completed,
                'course_features' => $course_features,
                'lesson_type' => $lesson_type,
                'assignment_learn' => $assignment_learn,
                'learn_curriculum_sidebar_scrollable' => self::isLearnCurriculumSidebarScrollableForCourse($course_id),
                'urls' => [
                    'courses' => get_post_type_archive_link(PostTypes::COURSE) ?: home_url('/'),
                    'login' => PublicPageUrls::login(get_permalink($post) ?: ''),
                    'course' => $course_post ? (get_permalink($course_post) ?: '') : '',
                    'learn' => PublicPageUrls::learnForCourse($course_id),
                    'account' => PublicPageUrls::url('account'),
                ],
                'rest' => [
                    'url' => esc_url_raw(rest_url('sikshya/v1/')),
                    'nonce' => wp_create_nonce('wp_rest'),
                ],
            ],
            $post
        );

        return SingleLessonPageModel::fromViewData(is_array($vm) ? $vm : []);
    }

    /**
     * Learner-facing assignment meta + submission snapshot for the Learn shell (null when not an assignment).
     *
     * @return array<string, mixed>|null
     */
    private static function buildAssignmentLearnPayload(
        \WP_Post $post,
        int $course_id,
        int $user_id,
        bool $enrolled,
        bool $is_preview
    ): ?array {
        if ($post->post_type !== PostTypes::ASSIGNMENT) {
            return null;
        }

        $aid = (int) $post->ID;
        $due_raw = (string) get_post_meta($aid, '_sikshya_assignment_due_date', true);
        $points = (int) get_post_meta($aid, '_sikshya_assignment_points', true);
        $stype = sanitize_key((string) get_post_meta($aid, '_sikshya_assignment_type', true));
        $allow_late = (string) get_post_meta($aid, '_sikshya_allow_late', true) === '1';

        $due_ts = $due_raw !== '' ? strtotime($due_raw) : 0;
        $now = (int) current_time('timestamp');
        $is_past_due = $due_ts > 0 && $now > $due_ts;

        $submission = null;
        if ($enrolled && !$is_preview && $user_id > 0) {
            $svc = new AssignmentService();
            $submission = $svc->getAssignmentFeedback($aid, $user_id);
        }

        $graded = is_array($submission) && (($submission['status'] ?? '') === 'graded');
        $allow_resubmit = is_array($submission) && !empty($submission['allow_resubmit']);
        $past_due_blocks = $is_past_due && !$allow_late && !($graded && $allow_resubmit);

        $can_submit = $enrolled && !$is_preview && !$past_due_blocks
            && (!$graded || $allow_resubmit);

        return [
            'assignment_id' => $aid,
            'points' => $points,
            'due_raw' => $due_raw,
            'due_formatted' => $due_ts > 0
                ? (string) wp_date(get_option('date_format') . ' ' . get_option('time_format'), $due_ts)
                : '',
            'submission_type' => $stype,
            'submission_type_label' => self::assignmentSubmissionTypeLabel($stype),
            'submission_subtype' => self::assignmentSubmissionSubtypeNormalized($stype),
            'min_files' => max(0, (int) get_post_meta($aid, '_sikshya_assignment_min_files', true)),
            'max_files' => max(0, (int) get_post_meta($aid, '_sikshya_assignment_max_files', true)),
            'require_text' => (string) get_post_meta($aid, '_sikshya_require_text', true) === '1',
            'allow_late' => $allow_late,
            'is_past_due' => $is_past_due,
            'can_submit' => $can_submit,
            'submission' => $submission,
        ];
    }

    /**
     * Canonical subtype for Learn UI + validation (matches {@see AssignmentService} rules).
     */
    private static function assignmentSubmissionSubtypeNormalized(string $raw): string
    {
        $raw = sanitize_key($raw);
        if ($raw === '') {
            return 'essay';
        }
        if (in_array($raw, ['file', 'file_upload'], true)) {
            return 'file_upload';
        }
        if (in_array($raw, ['text', 'essay'], true)) {
            return 'essay';
        }
        if ($raw === 'url_submission') {
            return 'url_submission';
        }

        return 'essay';
    }

    private static function assignmentSubmissionTypeLabel(string $stype): string
    {
        $labels = [
            'file' => __('File upload', 'sikshya'),
            'file_upload' => __('File upload', 'sikshya'),
            'text' => __('Essay', 'sikshya'),
            'essay' => __('Essay', 'sikshya'),
            'url_submission' => __('URL', 'sikshya'),
        ];

        return $stype !== '' && isset($labels[$stype]) ? $labels[$stype] : '';
    }

    /**
     * @param array<int, array{chapter: \WP_Post, items: array<int, array<string, mixed>>}> $blocks
     */
    private static function isCurrentCompleted(array $blocks): bool
    {
        foreach ($blocks as $block) {
            foreach ((array) ($block['items'] ?? []) as $item) {
                if (!empty($item['current'])) {
                    return !empty($item['completed']);
                }
            }
        }

        return false;
    }

    /**
     * Whether the current content is preview-accessible (guest or non-enrolled).
     *
     * Rule:
     * - If lesson meta `_sikshya_is_free` is truthy → allow preview
     *
     * @param array<int, array{chapter:\WP_Post, contents: array<int, \WP_Post>}> $raw_curriculum
     */
    private static function canPreviewContent(int $course_id, array $raw_curriculum, int $lesson_id): bool
    {
        $is_free = get_post_meta($lesson_id, '_sikshya_is_free', true);
        return Settings::isTruthy($is_free);
    }

    /**
     * Learn shell: keep the curriculum rail a fixed height and scroll the outline list (default).
     * Per-course opt-out when `_sikshya_learn_curriculum_sidebar_scrollable` is explicitly saved off.
     */
    public static function isLearnCurriculumSidebarScrollableForCourse(int $course_id): bool
    {
        if ($course_id <= 0) {
            return true;
        }
        $raw = get_post_meta($course_id, '_sikshya_learn_curriculum_sidebar_scrollable', true);
        if ($raw === '' || $raw === null || false === $raw) {
            return true;
        }

        return Settings::isTruthy($raw);
    }

    /**
     * Effective course features for Learn UI (global + per-course).
     *
     * @return array{reviews: bool, ratings: bool, discussions: bool, qa: bool, certificate: bool}
     */
    private static function courseFeatures(int $course_id): array
    {
        $global_reviews = Settings::isTruthy(Settings::get('enable_reviews', true));
        $global_ratings = Settings::isTruthy(Settings::get('enable_ratings', true));

        // These features may be enabled in settings/meta, but the actual Learn-page UI may not exist
        // unless a Pro/add-on provides it. Default to "not available" to avoid dead tabs.
        $reviews_available = (bool) apply_filters('sikshya_feature_reviews_available', false, $course_id, 'learn');
        $discussions_available = (bool) apply_filters('sikshya_feature_discussions_available', false, $course_id, 'learn');
        $qa_available = (bool) apply_filters('sikshya_feature_qa_available', false, $course_id, 'learn');

        return [
            'reviews' => $reviews_available
                && $global_reviews
                && Settings::isTruthy(get_post_meta($course_id, '_sikshya_enable_reviews', true)),
            'ratings' => $global_ratings,
            'discussions' => $discussions_available
                && (static function () use ($course_id): bool {
                    $raw = get_post_meta($course_id, '_sikshya_enable_discussions', true);
                    // Default ON unless explicitly disabled (empty meta means "use default").
                    return $raw === '' || Settings::isTruthy($raw);
                })(),
            'qa' => $qa_available
                && (static function () use ($course_id): bool {
                    $raw = get_post_meta($course_id, '_sikshya_enable_qa', true);
                    // Default OFF unless explicitly enabled.
                    return $raw !== '' && Settings::isTruthy($raw);
                })(),
            'certificate' => Settings::isTruthy(get_post_meta($course_id, '_sikshya_enable_certificate', true)),
        ];
    }

    /**
     * @param array<int, array{chapter: \WP_Post, items: array<int, array<string, mixed>>}> $blocks
     * @return \WP_Post|null
     */
    private static function currentChapterFor(array $blocks): ?\WP_Post
    {
        foreach ($blocks as $block) {
            foreach ((array) ($block['items'] ?? []) as $item) {
                if (!empty($item['current']) && isset($block['chapter']) && $block['chapter'] instanceof \WP_Post) {
                    return $block['chapter'];
                }
            }
        }

        return null;
    }

    /**
     * Resolve parent course for the Learn shell. Assignments use {@see LessonCourseLink::resolvedCourseIdForAssignment()}
     * because {@see LessonCourseLink::resolvedCourseIdForLesson()} only accepts lesson posts.
     */
    private static function lessonCourseId(\WP_Post $post): int
    {
        $id = (int) $post->ID;
        if ($post->post_type === PostTypes::ASSIGNMENT) {
            return LessonCourseLink::resolvedCourseIdForAssignment($id);
        }

        if ($post->post_type === PostTypes::LESSON) {
            return LessonCourseLink::resolvedCourseIdForLesson($id);
        }

        return 0;
    }

    /**
     * @param array<int, array{chapter: \WP_Post, contents: array<int, \WP_Post>}> $raw
     * @return array<int, array{chapter: \WP_Post, items: array<int, array<string, mixed>>, item_count: int, open: bool}>
     */
    private static function enrichBlocks(
        int $user_id,
        int $course_id,
        array $raw,
        int $current_post_id,
        bool $with_progress,
        bool $enrolled,
        bool $is_preview_mode
    ): array {
        $progress = new ProgressRepository();
        $out      = [];

        foreach ($raw as $row) {
            $chapter = $row['chapter'];
            $items   = [];
            $idx     = 0;

            foreach ($row['contents'] as $p) {
                if (!$p instanceof \WP_Post) {
                    continue;
                }

                ++$idx;

                $is_current = (int) $p->ID === $current_post_id;

                $type_key   = LearnOutlineItemAccess::contentTypeKey($p->post_type);
                $pto        = get_post_type_object($p->post_type);
                $type_label = $pto && isset($pto->labels->singular_name)
                    ? (string) $pto->labels->singular_name
                    : $p->post_type;

                $access = LearnOutlineItemAccess::forContentPost($p, $type_key, $course_id, $enrolled, $is_preview_mode);

                $item = [
                    'post' => $p,
                    'id' => (int) $p->ID,
                    'permalink' => $access['permalink'],
                    'title' => get_the_title($p),
                    'type_key' => $type_key,
                    'type_label' => $type_label,
                    'lesson_type' => $type_key === 'lesson' ? sanitize_key((string) get_post_meta((int) $p->ID, '_sikshya_lesson_type', true)) : '',
                    'meta_line' => CurriculumOutlineMeta::itemMetaLine($p, $type_key),
                    'duration_minutes' => CurriculumOutlineMeta::itemDurationMinutes($p, $type_key),
                    'subtitle_compact' => CurriculumOutlineMeta::itemSubtitleCompact($p, $type_key),
                    'index_in_section' => $idx,
                    'completed' => $with_progress ? self::isItemCompleted($progress, $user_id, $course_id, $p) : false,
                    'current' => $is_current,
                    'locked' => $access['locked'],
                    'lock_reason' => $access['lock_reason'],
                ];

                if ($enrolled) {
                    $item = apply_filters(
                        'sikshya_learn_outline_item',
                        $item,
                        [
                            'user_id' => $user_id,
                            'course_id' => $course_id,
                            'content_id' => (int) $p->ID,
                            'type' => $type_key,
                        ]
                    );
                }

                $items[] = is_array($item) ? $item : [
                    'post' => $p,
                    'id' => (int) $p->ID,
                    'permalink' => $access['permalink'],
                    'title' => get_the_title($p),
                    'type_key' => $type_key,
                    'type_label' => $type_label,
                    'lesson_type' => $type_key === 'lesson' ? sanitize_key((string) get_post_meta((int) $p->ID, '_sikshya_lesson_type', true)) : '',
                    'meta_line' => CurriculumOutlineMeta::itemMetaLine($p, $type_key),
                    'duration_minutes' => CurriculumOutlineMeta::itemDurationMinutes($p, $type_key),
                    'subtitle_compact' => CurriculumOutlineMeta::itemSubtitleCompact($p, $type_key),
                    'index_in_section' => $idx,
                    'completed' => $with_progress ? self::isItemCompleted($progress, $user_id, $course_id, $p) : false,
                    'current' => $is_current,
                    'locked' => $access['locked'],
                    'lock_reason' => $access['lock_reason'],
                ];
            }

            $completed_in_section = 0;
            $section_mins         = 0;
            foreach ($items as $it) {
                if ($with_progress && !empty($it['completed'])) {
                    ++$completed_in_section;
                }
                $section_mins += (int) ($it['duration_minutes'] ?? 0);
            }

            $out[] = [
                'chapter' => $chapter,
                'items' => $items,
                'item_count' => count($items),
                'completed_in_section' => $with_progress ? $completed_in_section : 0,
                'section_duration_minutes' => $section_mins,
                // Outline UI: all chapters expanded by default (see curriculum partial).
                'open' => true,
            ];
        }

        return $out;
    }

    private static function isItemCompleted(ProgressRepository $progress, int $user_id, int $course_id, \WP_Post $p): bool
    {
        if ($p->post_type === PostTypes::LESSON) {
            return $progress->hasLessonCompletion($user_id, $course_id, (int) $p->ID);
        }

        if ($p->post_type === PostTypes::QUIZ) {
            return $progress->hasQuizCompletion($user_id, $course_id, (int) $p->ID);
        }

        if ($p->post_type === PostTypes::ASSIGNMENT) {
            return $progress->hasLessonCompletion($user_id, $course_id, (int) $p->ID);
        }

        return false;
    }

    /**
     * @param array<int, array{chapter: \WP_Post, items: array<int, array<string, mixed>>, open: bool}> $blocks
     * @return array{total_items: int, completed_items: int, percent: int}
     */
    private static function computeStats(array $blocks): array
    {
        $total     = 0;
        $completed = 0;

        foreach ($blocks as $block) {
            foreach ($block['items'] as $item) {
                ++$total;
                if (!empty($item['completed'])) {
                    ++$completed;
                }
            }
        }

        $percent = $total > 0 ? (int) round(($completed / $total) * 100) : 0;

        return [
            'total_items' => $total,
            'completed_items' => $completed,
            'percent' => $percent,
        ];
    }

    /**
     * @param array<int, array{chapter: \WP_Post, items: array<int, array<string, mixed>>, open: bool}> $blocks
     * @return array{prev: string, next: string}
     */
    private static function computePrevNext(array $blocks, int $current_post_id): array
    {
        $flat = [];
        foreach ($blocks as $block) {
            foreach ($block['items'] as $item) {
                if (!empty($item['permalink'])) {
                    $flat[] = [
                        'id' => (int) ($item['id'] ?? 0),
                        'permalink' => (string) $item['permalink'],
                    ];
                }
            }
        }

        $prev = '';
        $next = '';
        foreach ($flat as $i => $row) {
            if ($row['id'] !== $current_post_id) {
                continue;
            }
            if ($i > 0) {
                $prev = $flat[$i - 1]['permalink'];
            }
            if ($i < count($flat) - 1) {
                $next = $flat[$i + 1]['permalink'];
            }
            break;
        }

        return [
            'prev' => $prev,
            'next' => $next,
        ];
    }
}
