<?php
declare(strict_types=1);

namespace Momentry;

use WP_REST_Request;
use WP_REST_Response;
use WP_Error;
use PDO;

defined('ABSPATH') || exit;

class Identity_API {
    private PDO $db;
    private string $schema;
    
    public function __construct() {
        $this->db = Database::get_instance();
        $this->schema = Database::get_schema();
    }
    
    public function register_routes(): void {
        register_rest_route('momentry/v1', '/identities', [
            'methods' => 'GET',
            'callback' => [$this, 'get_identities'],
            'permission_callback' => [$this, 'check_permission'],
        ]);
        
        register_rest_route('momentry/v1', '/identities/(?P<uuid>[a-f0-9\-]{36})', [
            'methods' => 'GET',
            'callback' => [$this, 'get_identity_detail'],
            'permission_callback' => [$this, 'check_permission'],
        ]);
        
        register_rest_route('momentry/v1', '/identities/(?P<uuid>[a-f0-9\-]{36})/angle-coverage', [
            'methods' => 'GET',
            'callback' => [$this, 'get_angle_coverage'],
            'permission_callback' => [$this, 'check_permission'],
        ]);
        
        register_rest_route('momentry/v1', '/identities/(?P<uuid>[a-f0-9\-]{36})/body-actions', [
            'methods' => 'GET',
            'callback' => [$this, 'get_body_actions'],
            'permission_callback' => [$this, 'check_permission'],
        ]);
        
        register_rest_route('momentry/v1', '/identities/(?P<uuid>[a-f0-9\-]{36})/reference-vectors', [
            'methods' => 'GET',
            'callback' => [$this, 'get_reference_vectors'],
            'permission_callback' => [$this, 'check_permission'],
        ]);
    }
    
    public function check_permission(): bool {
        return current_user_can('read') || $this->validate_api_key();
    }
    
    private function validate_api_key(): bool {
        $api_key = $_SERVER['HTTP_X_MOMENTRY_API_KEY'] ?? '';
        $valid_key = getenv('MOMENTRY_API_KEY');
        
        if (!$valid_key) {
            return false;
        }
        
        return hash_equals($valid_key, $api_key);
    }
    
    public function get_identities(WP_REST_Request $request): WP_REST_Response {
        $page = (int) $request->get_param('page') ?: 1;
        $per_page = (int) $request->get_param('per_page') ?: 50;
        $offset = ($page - 1) * $per_page;
        $search = $request->get_param('search');
        $source = $request->get_param('source');
        
        $sql = "SELECT 
            uuid,
            name,
            identity_type,
            source,
            tmdb_id,
            created_at,
            reference_data->>'total_references' as total_references,
            reference_data->>'quality_avg' as quality_avg,
            reference_data->'trace_stats'->>'duration_seconds' as trace_duration,
            reference_data->'trace_stats'->>'avg_confidence' as trace_confidence,
            reference_data->'trace_stats'->>'total_appearances' as trace_appearances
        FROM {$this->schema}.identities";
        
        $where = [];
        $params = [];
        
        if ($search) {
            $where[] = "name ILIKE ?";
            $params[] = "%{$search}%";
        }
        
        if ($source) {
            $where[] = "source = ?";
            $params[] = $source;
        }
        
        if (!empty($where)) {
            $sql .= " WHERE " . implode(' AND ', $where);
        }
        
        $sql .= " ORDER BY created_at DESC LIMIT ? OFFSET ?";
        $params[] = $per_page;
        $params[] = $offset;
        
        $stmt = $this->db->prepare($sql);
        $stmt->execute($params);
        $identities = $stmt->fetchAll(PDO::FETCH_ASSOC);
        
        $count_sql = "SELECT COUNT(*) FROM {$this->schema}.identities";
        if (!empty($where)) {
            $count_sql .= " WHERE " . implode(' AND ', $where);
        }
        $stmt = $this->db->prepare($count_sql);
        $stmt->execute(array_slice($params, 0, -2));
        $total = (int) $stmt->fetchColumn();
        
        $identities = array_map(function ($identity) {
            return $this->format_identity_list_item($identity);
        }, $identities);
        
        return new WP_REST_Response([
            'success' => true,
            'data' => $identities,
            'pagination' => [
                'page' => $page,
                'per_page' => $per_page,
                'total' => $total,
                'total_pages' => ceil($total / $per_page),
            ],
        ]);
    }
    
    public function get_identity_detail(WP_REST_Request $request): WP_REST_Response|WP_Error {
        $uuid = $request['uuid'];
        
        $sql = "SELECT 
            uuid,
            name,
            identity_type,
            source,
            tmdb_id,
            tmdb_profile,
            reference_data,
            created_at,
            updated_at
        FROM {$this->schema}.identities
        WHERE uuid = ?";
        
        $stmt = $this->db->prepare($sql);
        $stmt->execute([$uuid]);
        $identity = $stmt->fetch(PDO::FETCH_ASSOC);
        
        if (!$identity) {
            return new WP_Error(
                'not_found',
                'Identity not found',
                ['status' => 404]
            );
        }
        
        return new WP_REST_Response([
            'success' => true,
            'data' => $this->format_identity_detail($identity),
        ]);
    }
    
    public function get_angle_coverage(WP_REST_Request $request): WP_REST_Response|WP_Error {
        $uuid = $request['uuid'];
        
        $sql = "SELECT reference_data FROM {$this->schema}.identities WHERE uuid = ?";
        $stmt = $this->db->prepare($sql);
        $stmt->execute([$uuid]);
        $result = $stmt->fetch(PDO::FETCH_ASSOC);
        
        if (!$result) {
            return new WP_Error(
                'not_found',
                'Identity not found',
                ['status' => 404]
            );
        }
        
        $reference_data = json_decode($result['reference_data'], true);
        
        $angle_coverage = $this->calculate_angle_coverage($reference_data);
        
        return new WP_REST_Response([
            'success' => true,
            'data' => [
                'uuid' => $uuid,
                'angles' => $angle_coverage['angles'],
                'coverage_score' => $angle_coverage['score'],
                'recommendation' => $angle_coverage['recommendation'],
            ],
        ]);
    }
    
    public function get_body_actions(WP_REST_Request $request): WP_REST_Response|WP_Error {
        $uuid = $request['uuid'];
        
        $sql = "SELECT 
            i.uuid,
            i.name,
            i.reference_data
        FROM {$this->schema}.identities i
        WHERE i.uuid = ?";
        
        $stmt = $this->db->prepare($sql);
        $stmt->execute([$uuid]);
        $identity = $stmt->fetch(PDO::FETCH_ASSOC);
        
        if (!$identity) {
            return new WP_Error(
                'not_found',
                'Identity not found',
                ['status' => 404]
            );
        }
        
        $reference_data = json_decode($identity['reference_data'], true);
        $body_actions = $reference_data['body_actions'] ?? [];
        $action_statistics = $reference_data['action_statistics'] ?? [];
        
        return new WP_REST_Response([
            'success' => true,
            'data' => [
                'uuid' => $uuid,
                'name' => $identity['name'],
                'actions' => $body_actions,
                'statistics' => $action_statistics,
            ],
        ]);
    }
    
    public function get_reference_vectors(WP_REST_Request $request): WP_REST_Response|WP_Error {
        $uuid = $request['uuid'];
        
        $sql = "SELECT reference_data FROM {$this->schema}.identities WHERE uuid = ?";
        $stmt = $this->db->prepare($sql);
        $stmt->execute([$uuid]);
        $result = $stmt->fetch(PDO::FETCH_ASSOC);
        
        if (!$result) {
            return new WP_Error(
                'not_found',
                'Identity not found',
                ['status' => 404]
            );
        }
        
        $reference_data = json_decode($result['reference_data'], true);
        $face_embeddings = $reference_data['face_embeddings'] ?? [];
        
        $vectors = array_map(function ($embedding) {
            return [
                'angle' => $embedding['angle'] ?? 'unknown',
                'frame' => $embedding['frame'] ?? null,
                'quality_score' => $embedding['quality_score'] ?? 0,
                'pitch' => $embedding['pitch'] ?? 'neutral',
                'pose_confidence' => $embedding['pose_confidence'] ?? 0,
                'detection_confidence' => $embedding['detection_confidence'] ?? 0,
                'attributes' => [
                    'age' => $embedding['attributes']['age'] ?? null,
                    'gender' => $embedding['attributes']['gender'] ?? null,
                ],
            ];
        }, $face_embeddings);
        
        return new WP_REST_Response([
            'success' => true,
            'data' => [
                'uuid' => $uuid,
                'total_vectors' => count($vectors),
                'vectors' => $vectors,
            ],
        ]);
    }
    
    private function format_identity_list_item(array $identity): array {
        return [
            'uuid' => $identity['uuid'],
            'name' => $identity['name'],
            'type' => $identity['identity_type'],
            'source' => $identity['source'],
            'total_references' => (int) ($identity['total_references'] ?? 0),
            'quality_avg' => $identity['quality_avg'] ? round((float) $identity['quality_avg'], 3) : null,
            'trace_duration' => $identity['trace_duration'] ? round((float) $identity['trace_duration'], 2) : null,
            'trace_confidence' => $identity['trace_confidence'] ? round((float) $identity['trace_confidence'], 4) : null,
            'tmdb_id' => $identity['tmdb_id'],
            'created_at' => $identity['created_at'],
        ];
    }
    
    private function format_identity_detail(array $identity): array {
        $reference_data = json_decode($identity['reference_data'], true);
        
        return [
            'uuid' => $identity['uuid'],
            'name' => $identity['name'],
            'type' => $identity['identity_type'],
            'source' => $identity['source'],
            'tmdb_id' => $identity['tmdb_id'],
            'tmdb_profile' => $identity['tmdb_profile'],
            'reference_vectors' => [
                'total' => $reference_data['total_references'] ?? 0,
                'angles' => $reference_data['angles_covered'] ?? [],
                'quality_avg' => $reference_data['quality_avg'] ?? null,
            ],
            'trace_stats' => $reference_data['trace_stats'] ?? null,
            'created_at' => $identity['created_at'],
            'updated_at' => $identity['updated_at'],
        ];
    }
    
    private function calculate_angle_coverage(?array $reference_data): array {
        if (!$reference_data) {
            return [
                'angles' => [],
                'score' => 0,
                'recommendation' => 'No reference data available',
            ];
        }
        
        $face_embeddings = $reference_data['face_embeddings'] ?? [];
        $required_angles = ['frontal', 'three_quarter', 'profile_left', 'profile_right'];
        
        $angle_stats = [];
        foreach ($required_angles as $angle) {
            $angle_stats[$angle] = [
                'count' => 0,
                'quality_sum' => 0,
                'status' => 'missing',
            ];
        }
        
        foreach ($face_embeddings as $embedding) {
            $angle = $embedding['angle'] ?? 'unknown';
            $quality = $embedding['quality_score'] ?? 0;
            
            if (isset($angle_stats[$angle])) {
                $angle_stats[$angle]['count']++;
                $angle_stats[$angle]['quality_sum'] += $quality;
            }
        }
        
        $covered_count = 0;
        $total_quality = 0;
        
        foreach ($angle_stats as $angle => &$stats) {
            if ($stats['count'] > 0) {
                $stats['quality_avg'] = round($stats['quality_sum'] / $stats['count'], 3);
                $stats['status'] = $stats['count'] > 10 ? 'dominant' : 'present';
                $covered_count++;
                $total_quality += $stats['quality_avg'];
            }
            unset($stats['quality_sum']);
        }
        
        $coverage_score = round(($covered_count / count($required_angles)) * 100);
        $avg_quality = $covered_count > 0 ? round($total_quality / $covered_count, 3) : 0;
        
        $missing_angles = array_keys(array_filter($angle_stats, fn($s) => $s['count'] === 0));
        $recommendation = 'Excellent coverage!';
        
        if (count($missing_angles) > 0) {
            $recommendation = 'Add ' . implode(', ', $missing_angles) . ' angle(s) for better coverage';
        }
        
        return [
            'angles' => $angle_stats,
            'score' => $coverage_score,
            'quality_avg' => $avg_quality,
            'recommendation' => $recommendation,
        ];
    }
}