<?php
/**
 * Growth Achievements Controller
 *
 * REST API controller for the new achievements system
 * Replaces the old goals endpoints with achievement-based endpoints
 */

namespace FleekDash\Controllers;

use FleekDash\Core\AuthMiddleware;
use FleekDash\Models\GrowthAchievement;
use FleekDash\Services\GrowthAchievementsService;
use FleekDash\Traits\Base;

if (!\function_exists('fleekdash_log_debug')) {
    require_once FLEEKDASH_PLUGIN_DIR . 'includes/Core/debug-helpers.php';
}

class GrowthAchievementsController
{
    use Base;

    private GrowthAchievementsService $achievementsService;

    public function __construct()
    {
        $this->achievementsService = new GrowthAchievementsService();
    }

    /**
     * Check authentication status
     */
    private function checkAuth(string $required_level = 'authenticated'): array
    {
        try {
            $auth_check = AuthMiddleware::check($required_level);
            if (!$auth_check['authenticated']) {
                return [
                    'authenticated' => false,
                    'user_id' => 0,
                    'fallback' => true,
                    'reason' => $auth_check['reason']
                ];
            }

            return [
                'authenticated' => true,
                'user_id' => $auth_check['user_id'],
                'fallback' => false
            ];

        } catch (\Exception $e) {
            return [
                'authenticated' => false,
                'user_id' => 0,
                'fallback' => true,
                'reason' => 'Authentication error: ' . $e->getMessage()
            ];
        }
    }

    /**
     * Get all achievements
     * GET /wp-json/fleekdash/v1/growth-meter/achievements
     */
    public function get_achievements(\WP_REST_Request $request) // NOSONAR php:S100 — WP REST callback name
    {
        try {
            $auth = $this->checkAuth('public');

            $limit = $request->get_param('limit') ? intval($request->get_param('limit')) : null;
            $type_filter = $request->get_param('type');
            $period_filter = $request->get_param('period');

            $achievements = [];

            if ($type_filter) {
                $achievements = GrowthAchievement::getByType($type_filter, $limit);
            } elseif ($period_filter) {
                $achievements = GrowthAchievement::getByPeriod((string) $period_filter, $limit);
            } else {
                $achievements = GrowthAchievement::getAllAchievements($limit);
            }

            // Format achievements for frontend
            $formatted_achievements = array_map([$this, 'formatAchievement'], $achievements);

            return new \WP_REST_Response([
                'success' => true,
                'achievements' => $formatted_achievements,
                'count' => count($formatted_achievements),
                'auth_status' => [
                    'authenticated' => $auth['authenticated'],
                    'fallback' => $auth['fallback']
                ]
            ], 200);

        } catch (\Exception $e) {
            fleekdash_log_error('FleekDash: Error fetching achievements: ' . $e->getMessage());
            return new \WP_Error('achievements_error', $e->getMessage(), ['status' => 500]);
        }
    }

    /**
     * Get single achievement
     * GET /wp-json/fleekdash/v1/growth-meter/achievements/{id}
     */
    public function get_achievement(\WP_REST_Request $request) // NOSONAR php:S100 — WP REST callback name
    {
        try {
            $auth = $this->checkAuth('public');
            $achievement_id = $request->get_param('id');

            global $wpdb;
            $table = $wpdb->prefix . 'fleekdash_growth_achievements';

            $achievement = $wpdb->get_row(
                $wpdb->prepare("SELECT * FROM {$table} WHERE id = %d", $achievement_id),
                \ARRAY_A
            );

            if (!$achievement) {
                return new \WP_Error('achievement_not_found', 'Achievement not found', ['status' => 404]);
            }

            return new \WP_REST_Response([
                'success' => true,
                'achievement' => $this->formatAchievement($achievement),
                'auth_status' => [
                    'authenticated' => $auth['authenticated'],
                    'fallback' => $auth['fallback']
                ]
            ], 200);

        } catch (\Exception $e) {
            fleekdash_log_error('FleekDash: Error fetching achievement: ' . $e->getMessage());
            return new \WP_Error('achievement_error', $e->getMessage(), ['status' => 500]);
        }
    }

    /**
     * Get achievement statistics
     * GET /wp-json/fleekdash/v1/growth-meter/achievements/stats
     */
    public function get_achievement_stats(\WP_REST_Request $request) // NOSONAR php:S100,php:S1172 — WP REST callback; param unused
    {
        try {
            $auth = $this->checkAuth('public');
            $stats = $this->achievementsService->getAchievementStats();

            return new \WP_REST_Response([
                'success' => true,
                'stats' => $stats,
                'auth_status' => [
                    'authenticated' => $auth['authenticated'],
                    'fallback' => $auth['fallback']
                ]
            ], 200);

        } catch (\Exception $e) {
            fleekdash_log_error('FleekDash: Error fetching achievement stats: ' . $e->getMessage());
            return new \WP_Error('achievement_stats_error', $e->getMessage(), ['status' => 500]);
        }
    }

    /**
     * Get milestones only
     * GET /wp-json/fleekdash/v1/growth-meter/achievements/milestones
     */
    public function get_milestones(\WP_REST_Request $request) // NOSONAR php:S100 — WP REST callback name
    {
        try {
            $auth = $this->checkAuth('public');
            $limit = $request->get_param('limit') ? intval($request->get_param('limit')) : null;

            $milestones = GrowthAchievement::getMilestones($limit);
            $formatted_milestones = array_map([$this, 'formatAchievement'], $milestones);

            return new \WP_REST_Response([
                'success' => true,
                'milestones' => $formatted_milestones,
                'count' => count($formatted_milestones),
                'auth_status' => [
                    'authenticated' => $auth['authenticated'],
                    'fallback' => $auth['fallback']
                ]
            ], 200);

        } catch (\Exception $e) {
            fleekdash_log_error('FleekDash: Error fetching milestones: ' . $e->getMessage());
            return new \WP_Error('milestones_error', $e->getMessage(), ['status' => 500]);
        }
    }

    /**
     * Trigger achievement check (for testing/manual triggers)
     * POST /wp-json/fleekdash/v1/growth-meter/achievements/check
     */
    public function check_achievements(\WP_REST_Request $request) // NOSONAR php:S100,php:S1172 — WP REST callback; param unused
    {
        try {
            $auth = $this->checkAuth('authenticated');

            $result = $this->achievementsService->checkAndCreateAchievements();

            return new \WP_REST_Response([
                'success' => $result['success'],
                'achievements_created' => $result['achievements_created'] ?? 0,
                'achievements' => $result['achievements'] ?? [],
                'error' => $result['error'] ?? null,
                'auth_status' => [
                    'authenticated' => $auth['authenticated'],
                    'fallback' => $auth['fallback']
                ]
            ], 200);

        } catch (\Exception $e) {
            fleekdash_log_error('FleekDash: Error checking achievements: ' . $e->getMessage());
            return new \WP_Error('achievement_check_error', $e->getMessage(), ['status' => 500]);
        }
    }

    /**
     * Get achievements grouped by period for the main interface
     * GET /wp-json/fleekdash/v1/growth-meter/achievements/grouped
     */
    public function get_achievements_grouped(\WP_REST_Request $request) // NOSONAR php:S100,php:S1172 — WP REST callback; param unused
    {
        try {
            $auth = $this->checkAuth('public');

            $grouped_achievements = [
                'latest_7_days' => $this->getAchievementsInPeriod(7),
                'latest_30_days' => $this->getAchievementsInPeriod(30),
                'milestones' => GrowthAchievement::getMilestones(5),
                'all_time_records' => GrowthAchievement::getByType(GrowthAchievement::TYPE_ALL_TIME_RECORD, 5)
            ];

            // Format all achievements
            foreach ($grouped_achievements as $key => $achievements) {
                $grouped_achievements[$key] = array_map([$this, 'formatAchievement'], $achievements);
            }

            return new \WP_REST_Response([
                'success' => true,
                'grouped_achievements' => $grouped_achievements,
                'auth_status' => [
                    'authenticated' => $auth['authenticated'],
                    'fallback' => $auth['fallback']
                ]
            ], 200);

        } catch (\Exception $e) {
            fleekdash_log_error('FleekDash: Error fetching grouped achievements: ' . $e->getMessage());
            return new \WP_Error('grouped_achievements_error', $e->getMessage(), ['status' => 500]);
        }
    }

    /**
     * Get achievements in a specific time period
     */
    private function getAchievementsInPeriod(int $days): array
    {
        global $wpdb;
        $table = $wpdb->prefix . 'fleekdash_growth_achievements';

        $date_threshold = date('Y-m-d H:i:s', strtotime("-{$days} days"));

        return $wpdb->get_results(
            $wpdb->prepare(
                "SELECT * FROM {$table} WHERE achieved_at >= %s ORDER BY achieved_at DESC",
                $date_threshold
            ),
            \ARRAY_A
        );
    }

    /**
     * Format achievement for API response
     *
     * @param array<string, mixed>|null $achievement
     * @return array<string, mixed>|null
     */
    private function formatAchievement(?array $achievement): ?array
    {
        if (!$achievement) {
            return null;
        }

        // Decode JSON fields
        $points_breakdown = json_decode($achievement['points_breakdown'] ?? '{}', true) ?: [];

        return [
            'id' => intval($achievement['id']),
            'achievement_type' => $achievement['achievement_type'],
            'achievement_name' => $achievement['achievement_name'],
            'description' => $achievement['description'],
            'period_type' => $achievement['period_type'],
            'record_value' => intval($achievement['record_value']),
            'previous_record' => intval($achievement['previous_record']),
            'improvement' => intval($achievement['record_value']) - intval($achievement['previous_record']),
            'achieved_at' => $achievement['achieved_at'],
            'achieved_at_formatted' => date('M j, Y', strtotime($achievement['achieved_at'])),
            'achieved_at_relative' => human_time_diff(strtotime($achievement['achieved_at'])) . ' ago',
            'points_breakdown' => $points_breakdown,
            'achievement_icon' => $achievement['achievement_icon'],
            'achievement_color' => $achievement['achievement_color'],
            'is_milestone' => (bool) $achievement['is_milestone'],
            'milestone_level' => intval($achievement['milestone_level']),
            // Additional computed fields for UI
            'category' => $this->getAchievementCategory((string) ($achievement['achievement_type'] ?? '')),
            'rarity' => $this->getAchievementRarity($achievement),
            'display_value' => $this->formatDisplayValue(intval($achievement['record_value']))
        ];
    }

    /**
     * Get achievement category for UI grouping
     */
    private function getAchievementCategory(string $type): string
    {
        $categories = [
            GrowthAchievement::TYPE_DAILY_RECORD => 'Daily Records',
            GrowthAchievement::TYPE_WEEKLY_RECORD => 'Weekly Records',
            GrowthAchievement::TYPE_MONTHLY_RECORD => 'Monthly Records',
            GrowthAchievement::TYPE_ALL_TIME_RECORD => 'All-Time Records',
            GrowthAchievement::TYPE_STREAK_MILESTONE => 'Streaks',
            GrowthAchievement::TYPE_POINTS_MILESTONE => 'Milestones'
        ];

        return $categories[$type] ?? 'Other';
    }

    /**
     * Get achievement rarity for UI styling
     *
     * @param array<string, mixed> $achievement
     */
    private function getAchievementRarity(array $achievement): string
    {
        $record_value = intval($achievement['record_value']);
        $is_milestone = (bool) $achievement['is_milestone'];
        $rarity = 'common';

        if ($is_milestone) {
            if ($record_value >= 100000) {
                $rarity = 'legendary';
            } elseif ($record_value >= 25000) {
                $rarity = 'epic';
            } elseif ($record_value >= 5000) {
                $rarity = 'rare';
            }
        } else {
            $improvement = intval($achievement['record_value']) - intval($achievement['previous_record']);
            if ($improvement >= 1000) {
                $rarity = 'legendary';
            } elseif ($improvement >= 500) {
                $rarity = 'epic';
            } elseif ($improvement >= 100) {
                $rarity = 'rare';
            }
        }

        return $rarity;
    }

    /**
     * Format display value with appropriate units
     */
    private function formatDisplayValue(int $value): string
    {
        $normalized = $value;

        if ($normalized >= 1000000) {
            return number_format($normalized / 1000000, 1) . 'M';
        }

        if ($normalized >= 1000) {
            return number_format($normalized / 1000, 1) . 'K';
        }

        return number_format($normalized);
    }
}
