<?php

namespace ZenoChatbot\Http\Controller\Api\V1;

use ZenoChatbot\Framework\Http\Request;
use ZenoChatbot\Model\SavedReply;
use ZenoChatbot\Helper\Settings;
use ZenoChatbot\Services\Chat\Embedding\EmbeddingService;

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

/**
 * Saved Reply API Controller
 *
 * Handles CRUD operations for saved replies
 */
class SavedReplyController
{
    /**
     * List saved replies with pagination and filters
     */
    public function index(Request $request)
    {
        $filters = $request->getSafe([
            'search' => 'sanitize_text_field',
            'status' => 'sanitize_text_field',
            'match_type' => 'sanitize_text_field',
            'language' => 'sanitize_text_field',
        ]);

        $query = SavedReply::query();

        // Search filter
        if (!empty($filters['search'])) {
            $search = '%' . $filters['search'] . '%';
            $query->where(function($q) use ($search) {
                $q->where('question', 'LIKE', $search)
                  ->orWhere('keywords', 'LIKE', $search)
                  ->orWhere('answer', 'LIKE', $search);
            });
        }

        // Status filter
        if (!empty($filters['status'])) {
            if ($filters['status'] === 'active') {
                $query->where('is_active', 1);
            } elseif ($filters['status'] === 'inactive') {
                $query->where('is_active', 0);
            }
        }

        // Match type filter
        if (!empty($filters['match_type'])) {
            $query->where('match_type', $filters['match_type']);
        }

        // Language filter
        if (!empty($filters['language'])) {
            $query->where('language', $filters['language']);
        }

        $paginator = $query
            ->orderBy('priority', 'desc')
            ->orderBy('created_at', 'desc')
            ->paginate();

        return [
            'success' => true,
            'data' => [
                'replies' => $paginator->items()->toArray(),
                'pagination' => $paginator->getPaginationInfo(),
            ],
            'filters' => $filters
        ];
    }

    /**
     * Get a single saved reply
     */
    public function show($id)
    {
        try {
            $reply = SavedReply::query()->findOrFail($id);
            return ['success' => true, 'data' => $reply];
        } catch (\Exception $e) {
            return ['success' => false, 'message' => 'Saved reply not found', 'status' => 404];
        }
    }

    /**
     * Create a new saved reply
     */
    public function store(Request $request)
    {
        $data = $request->getSafe([
            'question' => 'sanitize_textarea_field',
            'answer' => 'sanitize_textarea_field',
            'match_type' => 'sanitize_text_field',
            'keywords' => 'sanitize_text_field',
            'language' => 'sanitize_text_field',
            'priority' => 'absint',
            'is_active' => 'absint',
        ]);

        if (empty($data['question'])) {
            return ['success' => false, 'message' => 'Question is required', 'status' => 400];
        }
        if (empty($data['answer'])) {
            return ['success' => false, 'message' => 'Answer is required', 'status' => 400];
        }

        $data['match_type'] = $data['match_type'] ?: 'exact';
        $data['language'] = $data['language'] ?: 'en';
        $data['priority'] = $data['priority'] ?? 50;
        $data['is_active'] = isset($data['is_active']) ? (int) $data['is_active'] : 1;
        $data['hit_count'] = 0;

        try {
            $reply = SavedReply::create($data);
            return ['success' => true, 'message' => 'Saved reply created successfully', 'data' => $reply];
        } catch (\Exception $e) {
            return [
                'success' => false,
                'message' => 'Failed to create saved reply',
                'error' => WP_DEBUG ? $e->getMessage() : 'Internal server error',
                'status' => 500
            ];
        }
    }

    /**
     * Update an existing saved reply
     */
    public function update($id, Request $request)
    {
        try {
            $reply = SavedReply::query()->findOrFail($id);
        } catch (\Exception $e) {
            return ['success' => false, 'message' => 'Saved reply not found', 'status' => 404];
        }

        // Build the update set from fields actually present in the request, so a
        // partial update only touches what was sent. Unlike array_filter(), this
        // lets an intentionally cleared field (e.g. keywords) be saved as empty.
        $sanitizers = [
            'question' => 'sanitize_textarea_field',
            'answer' => 'sanitize_textarea_field',
            'match_type' => 'sanitize_text_field',
            'keywords' => 'sanitize_text_field',
            'language' => 'sanitize_text_field',
            'priority' => 'absint',
            'is_active' => 'absint',
        ];

        $updateData = [];
        foreach ($sanitizers as $field => $sanitizer) {
            if (!$request->has($field)) {
                continue;
            }

            $value = $request->input($field);
            $updateData[$field] = function_exists($sanitizer)
                ? call_user_func($sanitizer, $value)
                : sanitize_text_field($value);
        }

        // Required fields may be omitted (partial update), but never blanked.
        if (array_key_exists('question', $updateData) && trim((string) $updateData['question']) === '') {
            return ['success' => false, 'message' => 'Question cannot be empty', 'status' => 400];
        }
        if (array_key_exists('answer', $updateData) && trim((string) $updateData['answer']) === '') {
            return ['success' => false, 'message' => 'Answer cannot be empty', 'status' => 400];
        }

        if (empty($updateData)) {
            return ['success' => true, 'message' => 'Nothing to update', 'data' => $reply];
        }

        try {
            $reply->update($updateData);
            return ['success' => true, 'message' => 'Saved reply updated successfully', 'data' => $reply];
        } catch (\Exception $e) {
            return [
                'success' => false,
                'message' => 'Failed to update saved reply',
                'error' => WP_DEBUG ? $e->getMessage() : 'Internal server error',
                'status' => 500
            ];
        }
    }

    /**
     * Delete a saved reply
     */
    public function destroy($id)
    {
        try {
            $reply = SavedReply::query()->findOrFail($id);
            $reply->delete();
            return ['success' => true, 'message' => 'Saved reply deleted successfully'];
        } catch (\Exception $e) {
            return [
                'success' => false,
                'message' => 'Failed to delete saved reply',
                'error' => WP_DEBUG ? $e->getMessage() : 'Internal server error',
                'status' => 500
            ];
        }
    }

    /**
     * Toggle active status
     */
    public function toggleStatus($id)
    {
        try {
            $reply = SavedReply::query()->findOrFail($id);
            $reply->update(['is_active' => $reply->is_active ? 0 : 1]);
            return [
                'success' => true,
                'message' => $reply->is_active ? 'Reply activated' : 'Reply deactivated',
                'data' => $reply
            ];
        } catch (\Exception $e) {
            return [
                'success' => false,
                'message' => 'Failed to toggle status',
                'error' => WP_DEBUG ? $e->getMessage() : 'Internal server error',
                'status' => 500
            ];
        }
    }

    /**
     * Get semantic matching settings
     */
    public function getSemanticSettings()
    {
        $enabled = (bool) Settings::get('saved_replies.semantic_enabled', false);
        $threshold = (float) Settings::get('saved_replies.semantic_threshold', 0.75);

        // Get embedding stats from service
        $service = new EmbeddingService();
        $stats = $service->getStats();

        return [
            'success' => true,
            'data' => [
                'enabled' => $enabled,
                'threshold' => $threshold,
                'status' => $stats,
            ],
        ];
    }

    /**
     * Update semantic matching settings
     */
    public function updateSemanticSettings(Request $request)
    {
        $data = $request->getSafe([
            'enabled' => 'rest_sanitize_boolean',
            'threshold' => 'floatval',
        ]);

        if (isset($data['enabled'])) {
            Settings::update('saved_replies.semantic_enabled', (bool) $data['enabled']);
        }

        if (isset($data['threshold'])) {
            $threshold = max(0.5, min(0.95, (float) $data['threshold']));
            Settings::update('saved_replies.semantic_threshold', $threshold);
        }

        return [
            'success' => true,
            'message' => 'Semantic settings updated successfully',
        ];
    }

    /**
     * Generate embeddings for saved replies without embeddings
     */
    public function generateEmbeddings()
    {
        try {
            $service = new EmbeddingService();
            $result = $service->generateForAll();

            return [
                'success' => true,
                'message' => sprintf(
                    'Generated embeddings for %d replies (%d failed, %d skipped)',
                    $result['success'],
                    $result['failed'],
                    $result['skipped']
                ),
                'data' => $result,
            ];
        } catch (\Exception $e) {
            return [
                'success' => false,
                'message' => 'Failed to generate embeddings: ' . $e->getMessage(),
                'status' => 500,
            ];
        }
    }

    /**
     * Regenerate all embeddings
     */
    public function regenerateAllEmbeddings()
    {
        try {
            $service = new EmbeddingService();
            $result = $service->regenerateAll();

            return [
                'success' => true,
                'message' => sprintf(
                    'Regenerated embeddings for %d replies (%d failed, %d skipped)',
                    $result['success'],
                    $result['failed'],
                    $result['skipped']
                ),
                'data' => $result,
            ];
        } catch (\Exception $e) {
            return [
                'success' => false,
                'message' => 'Failed to regenerate embeddings: ' . $e->getMessage(),
                'status' => 500,
            ];
        }
    }

    /**
     * Clear all embeddings
     */
    public function clearEmbeddings()
    {
        try {
            $service = new EmbeddingService();
            $cleared = $service->clearAll();

            return [
                'success' => true,
                'message' => sprintf('Cleared embeddings for %d replies', $cleared),
                'data' => ['cleared' => $cleared],
            ];
        } catch (\Exception $e) {
            return [
                'success' => false,
                'message' => 'Failed to clear embeddings: ' . $e->getMessage(),
                'status' => 500,
            ];
        }
    }

    /**
     * Get analytics data for saved replies
     */
    public function getAnalytics()
    {
        try {
            // Get all replies for analytics
            $allReplies = SavedReply::query()->get();

            $total = count($allReplies);
            $active = 0;
            $inactive = 0;
            $totalHits = 0;
            $matchTypeDistribution = [];
            $topPerformers = [];
            $unusedReplies = [];

            foreach ($allReplies as $reply) {
                // Count active/inactive
                if ($reply->is_active) {
                    $active++;
                } else {
                    $inactive++;
                }

                // Sum hits
                $totalHits += (int) $reply->hit_count;

                // Match type distribution
                $matchType = $reply->match_type ?? 'exact';
                if (!isset($matchTypeDistribution[$matchType])) {
                    $matchTypeDistribution[$matchType] = 0;
                }
                $matchTypeDistribution[$matchType]++;

                // Format created_at for JSON
                $createdAt = $reply->created_at;
                if ($createdAt instanceof \DateTime) {
                    $createdAt = $createdAt->format('Y-m-d H:i:s');
                }

                // Collect for sorting
                $topPerformers[] = [
                    'id' => $reply->id,
                    'question' => $reply->question,
                    'match_type' => $reply->match_type,
                    'hit_count' => (int) $reply->hit_count,
                    'created_at' => $createdAt,
                ];

                // Unused replies (0 hits)
                if ((int) $reply->hit_count === 0) {
                    $unusedReplies[] = [
                        'id' => $reply->id,
                        'question' => $reply->question,
                        'match_type' => $reply->match_type,
                        'created_at' => $createdAt,
                    ];
                }
            }

            // Sort top performers by hit_count descending
            usort($topPerformers, function ($a, $b) {
                return $b['hit_count'] - $a['hit_count'];
            });

            // Take top 5
            $topPerformers = array_slice($topPerformers, 0, 5);

            // Sort unused by created_at descending (newest first)
            usort($unusedReplies, function ($a, $b) {
                return strtotime($b['created_at'] ?? '0') - strtotime($a['created_at'] ?? '0');
            });

            // Calculate average hits
            $avgHits = $total > 0 ? $totalHits / $total : 0;

            return [
                'success' => true,
                'data' => [
                    'total' => $total,
                    'active' => $active,
                    'inactive' => $inactive,
                    'total_hits' => $totalHits,
                    'avg_hits' => round($avgHits, 2),
                    'match_type_distribution' => $matchTypeDistribution,
                    'top_performers' => $topPerformers,
                    'unused_replies' => $unusedReplies,
                ],
            ];
        } catch (\Exception $e) {
            return [
                'success' => false,
                'message' => 'Failed to load analytics: ' . $e->getMessage(),
                'status' => 500,
            ];
        }
    }
}
