<?php

namespace App\Http\Controllers;

require_once __DIR__ . '/../../../vendor/autoload.php';

use App\Config\AuthServiceConfig;
use Firebase\JWT\JWT;
use Firebase\JWT\Key;
use Exception;
use PDO;
use PDOException;

/**
 * Auth Microservice Controller
 * Handles registration, login, token validation, and user authentication
 * 
 * Database: emmanylcode_auth
 * 
 * @category Authentication
 * @package App\Http\Controllers
 * @author Architecture Team
 * @version 1.0.0
 */
class AuthServiceController
{
    private $db;
    private $config;
    private $httpCode = 200;
    private $responseHeaders = ['Content-Type' => 'application/json'];

    public function __construct()
    {
        $this->config = AuthServiceConfig::getConfig();
        
        try {
            $driver = AuthServiceConfig::getDatabase();
            $this->db = $driver->getConnection();
        } catch (Exception $e) {
            $this->sendResponse([
                'error' => 'Database connection failed',
                'message' => 'Unable to connect to authentication database'
            ], 503);
            exit;
        }
    }

    /**
     * Handle CORS preflight requests
     */
    public function handleCors()
    {
        if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
            $origin = $_SERVER['HTTP_ORIGIN'] ?? '*';
            header('Access-Control-Allow-Origin: ' . $origin);
            header('Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS');
            header('Access-Control-Allow-Headers: Content-Type, Authorization, x-api-key');
            header('Access-Control-Allow-Credentials: true');
            exit(0);
        }
    }

    /**
     * Register new user
     * POST /api/auth/register
     * 
     * @return void
     */
    public function register(): void
    {
        try {
            // Get JSON input
            $input = $this->getJsonInput();

            // Validate required fields
            $required = ['name', 'email', 'password', 'phone', 'address'];
            foreach ($required as $field) {
                if (empty($input[$field])) {
                    $this->sendResponse([
                        'error' => "Missing required field: $field",
                        'field' => $field
                    ], 400);
                    return;
                }
            }

            // Sanitize inputs
            $name = trim($input['name']);
            $email = filter_var(trim($input['email']), FILTER_SANITIZE_EMAIL);
            $password = trim($input['password']);
            $phone = trim($input['phone']);
            $address = trim($input['address']);
            $role_id = isset($input['role_id']) ? (int)$input['role_id'] : 5;

            // Validate email format
            if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
                $this->sendResponse([
                    'error' => 'Invalid email format',
                    'field' => 'email'
                ], 400);
                return;
            }

            // Validate password strength (minimum 8 characters)
            if (strlen($password) < 8) {
                $this->sendResponse([
                    'error' => 'Password must be at least 8 characters',
                    'field' => 'password'
                ], 400);
                return;
            }

            // Check if email already exists (auth_users)
            $checkQuery = "SELECT id FROM auth_users WHERE email = :email LIMIT 1";
            $checkStmt = $this->db->prepare($checkQuery);
            $checkStmt->execute(['email' => $email]);

            if ($checkStmt->fetch()) {
                $this->sendResponse([
                    'error' => 'Email already registered',
                    'field' => 'email'
                ], 409);
                return;
            }

            // Hash password
            $hashedPassword = password_hash($password, PASSWORD_BCRYPT, ['cost' => 12]);

            // Insert user into auth_users (status_id default to Active if not supplied)
            $statusId = isset($input['status_id']) ? (int)$input['status_id'] : 142345678901234591;
            $username = isset($input['username']) ? trim($input['username']) : preg_replace('/\s+/', '_', strtolower($name));

            $insertQuery = "
                INSERT INTO auth_users (name, username, email, password, phone, address, role_id, status_id, created_at, updated_at)
                VALUES (:name, :username, :email, :password, :phone, :address, :role_id, :status_id, NOW(), NOW())
            ";
            
            $insertStmt = $this->db->prepare($insertQuery);
            $result = $insertStmt->execute([
                'name' => $name,
                'username' => $username,
                'email' => $email,
                'password' => $hashedPassword,
                'phone' => $phone,
                'address' => $address,
                'role_id' => $role_id
                , 'status_id' => $statusId
            ]);

            if (!$result) {
                $this->sendResponse([
                    'error' => 'Failed to create user account',
                    'details' => $insertStmt->errorInfo()
                ], 500);
                return;
            }

            $userId = $this->db->lastInsertId();

            $this->sendResponse([
                'message' => 'Registration successful',
                    'user' => [
                        'id' => (int)$userId,
                        'name' => $name,
                        'username' => $username,
                        'email' => $email,
                        'phone' => $phone,
                        'address' => $address,
                        'role_id' => $role_id,
                        'status_id' => $statusId
                    ]
            ], 201);

        } catch (PDOException $e) {
            error_log("Database error in register: " . $e->getMessage());
            $this->sendResponse([
                'error' => 'Database error',
                'message' => 'An error occurred while processing your request'
            ], 500);
        } catch (Exception $e) {
            error_log("Error in register: " . $e->getMessage());
            $this->sendResponse([
                'error' => 'Server error',
                'message' => $e->getMessage()
            ], 500);
        }
    }

    /**
     * Login user
     * POST /api/auth/login
     * 
     * @return void
     */
    public function login(): void
    {
        try {
            $input = $this->getJsonInput();

            // Validate required fields
            if (empty($input['email']) || empty($input['password'])) {
                $this->sendResponse([
                    'error' => 'Email and password are required'
                ], 400);
                return;
            }

            $email = filter_var(trim($input['email']), FILTER_SANITIZE_EMAIL);
            $password = trim($input['password']);

            // Find user
            $query = "SELECT id, name, username, email, password, phone, address, role_id, status_id FROM auth_users WHERE email = :email LIMIT 1";
            $stmt = $this->db->prepare($query);
            $stmt->execute(['email' => $email]);
            $user = $stmt->fetch(PDO::FETCH_ASSOC);

            if (!$user || !password_verify($password, $user['password'])) {
                $this->sendResponse([
                    'error' => 'Invalid email or password'
                ], 401);
                return;
            }

            // Generate JWT token (RS256)
            $token = $this->generateToken((int)$user['id'], (int)$user['role_id']);

            $this->sendResponse([
                'message' => 'Login successful',
                'user' => [
                    'id' => (int)$user['id'],
                    'name' => $user['name'],
                    'email' => $user['email'],
                    'phone' => $user['phone'],
                    'address' => $user['address'],
                    'role_id' => (int)$user['role_id'],
                    'status_id' => (int)$user['status_id']
                ],
                'token' => $token
            ], 200);

        } catch (Exception $e) {
            error_log("Error in login: " . $e->getMessage());
            $this->sendResponse([
                'error' => 'Server error',
                'message' => $e->getMessage()
            ], 500);
        }
    }

    /**
     * Validate token
     * POST /api/auth/validate-token
     * 
     * @return void
     */
    public function validateToken(): void
    {
        try {
            $input = $this->getJsonInput();

            if (empty($input['token'])) {
                $this->sendResponse(['error' => 'Token is required'], 400);
                return;
            }

            // Implement token validation logic
            if ($this->verifyToken($input['token'])) {
                $this->sendResponse(['message' => 'Token is valid'], 200);
            } else {
                $this->sendResponse(['error' => 'Invalid token'], 401);
            }
        } catch (Exception $e) {
            $this->sendResponse(['error' => 'Server error'], 500);
        }
    }

    /**
     * List all roles
     * GET /api/auth/roles
     */
    public function listRoles(): void
    {
        try {
            $query = "SELECT id, name, slug FROM auth_roles ORDER BY id ASC";
            $stmt = $this->db->query($query);
            $roles = $stmt->fetchAll(PDO::FETCH_ASSOC);

            $this->sendResponse(['roles' => $roles], 200);
        } catch (Exception $e) {
            $this->sendResponse(['error' => 'Failed to fetch roles'], 500);
        }
    }

    /**
     * List all statuses
     * GET /api/auth/statuses
     */
    public function listStatuses(): void
    {
        try {
            $query = "SELECT id, name, slug FROM auth_statuses ORDER BY id ASC";
            $stmt = $this->db->query($query);
            $statuses = $stmt->fetchAll(PDO::FETCH_ASSOC);

            $this->sendResponse(['statuses' => $statuses], 200);
        } catch (Exception $e) {
            $this->sendResponse(['error' => 'Failed to fetch statuses'], 500);
        }
    }

    /**
     * Get JSON input from request
     * 
     * @return array
     */
    private function getJsonInput(): array
    {
        $input = file_get_contents('php://input');
        
        if (empty($input)) {
            return [];
        }

        $decoded = json_decode($input, true);
        
        if (json_last_error() !== JSON_ERROR_NONE) {
            throw new Exception('Invalid JSON: ' . json_last_error_msg());
        }

        return $decoded ?? [];
    }

    /**
     * Generate JWT token (simplified implementation)
     * 
     * @param int $userId
     * @return string
     */
    private function generateToken(int $userId): string
    {
        $cfg = $this->config['jwt'];

        $payload = [
            'user_id' => $userId,
            'iat' => time(),
            'exp' => time() + ($cfg['expiration'] ?? 3600),
            'iss' => $cfg['issuer'] ?? 'emmanylcode-auth'
        ];

        $privateKey = $cfg['private_key'] ?? null;

        if (empty($privateKey)) {
            // Fallback to HMAC if private key missing
            $secret = $cfg['secret'] ?? 'auth-service-secret-key';
            return JWT::encode($payload, $secret, 'HS256');
        }

        return JWT::encode($payload, $privateKey, $cfg['alg'] ?? 'RS256');
    }

    /**
     * Verify JWT token (simplified implementation)
     * 
     * @param string $token
     * @return bool
     */
    private function verifyToken(string $token): bool
    {
        $cfg = $this->config['jwt'];

        $publicKey = $cfg['public_key'] ?? null;

        try {
            if (!empty($publicKey)) {
                $decoded = JWT::decode($token, new Key($publicKey, $cfg['alg'] ?? 'RS256'));
            } else {
                // fallback to HMAC
                $secret = $cfg['secret'] ?? 'auth-service-secret-key';
                $decoded = JWT::decode($token, new Key($secret, 'HS256'));
            }

            if (isset($decoded->exp) && $decoded->exp < time()) {
                return false;
            }

            return true;
        } catch (\Exception $e) {
            error_log('Token verification failed: ' . $e->getMessage());
            return false;
        }
    }

    /**
     * Send JSON response
     * 
     * @param array $data
     * @param int $httpCode
     * @return void
     */
    private function sendResponse(array $data, int $httpCode = 200): void
    {
        header('Content-Type: application/json');
        header('Access-Control-Allow-Origin: *');
        header('Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS');
        header('Access-Control-Allow-Headers: Content-Type, Authorization, x-api-key');
        
        http_response_code($httpCode);
        echo json_encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);
    }
}
