<?php
/**
 * Geolocation IP Tracker API
 * Author: RSK World
 * Founder: Molla Samser
 * Designer & Tester: Rima Khatun
 * Website: https://rskworld.in
 * Contact: help@rskworld.in, +91 93305 39277
 * Year: 2026
 * Description: Advanced IP geolocation tracking and detailed location information retrieval
 */

header('Content-Type: application/json');
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: GET, POST, OPTIONS');
header('Access-Control-Allow-Headers: Content-Type');

if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
    exit(0);
}

class GeolocationTracker {
    private $apiKey;
    private $cacheFile = 'cache/geolocation_cache.json';
    private $cacheExpiry = 3600; // 1 hour
    
    public function __construct() {
        $this->apiKey = 'free'; // Using free ip-api.com service
        $this->ensureCacheDirectory();
    }
    
    private function ensureCacheDirectory() {
        if (!file_exists('cache')) {
            mkdir('cache', 0755, true);
        }
    }
    
    private function getCachedData($ip) {
        if (!file_exists($this->cacheFile)) {
            return null;
        }
        
        $cache = json_decode(file_get_contents($this->cacheFile), true);
        if (!$cache || !isset($cache[$ip])) {
            return null;
        }
        
        $data = $cache[$ip];
        if (time() - $data['timestamp'] > $this->cacheExpiry) {
            return null;
        }
        
        return $data['location'];
    }
    
    private function setCachedData($ip, $data) {
        $cache = [];
        if (file_exists($this->cacheFile)) {
            $cache = json_decode(file_get_contents($this->cacheFile), true) ?: [];
        }
        
        $cache[$ip] = [
            'location' => $data,
            'timestamp' => time()
        ];
        
        file_put_contents($this->cacheFile, json_encode($cache));
    }
    
    private function validateIP($ip) {
        // Accept all valid IPs including private ones for testing
        return filter_var($ip, FILTER_VALIDATE_IP) !== false;
    }
    
    private function getClientIP() {
        // Check for shared internet/ISP IP
        if (!empty($_SERVER['HTTP_CLIENT_IP'])) {
            $ip = $_SERVER['HTTP_CLIENT_IP'];
        }
        // Check for IP passing through proxy
        elseif (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
            $ip = $_SERVER['HTTP_X_FORWARDED_FOR'];
        }
        // Check for IP from load balancer
        elseif (!empty($_SERVER['HTTP_X_FORWARDED'])) {
            $ip = $_SERVER['HTTP_X_FORWARDED'];
        }
        // Check for IP from load balancer
        elseif (!empty($_SERVER['HTTP_FORWARDED_FOR'])) {
            $ip = $_SERVER['HTTP_FORWARDED_FOR'];
        }
        // Check for IP from load balancer
        elseif (!empty($_SERVER['HTTP_FORWARDED'])) {
            $ip = $_SERVER['HTTP_FORWARDED'];
        }
        // Standard remote address
        else {
            $ip = $_SERVER['REMOTE_ADDR'] ?? '127.0.0.1';
        }
        
        // Handle multiple IPs (comma separated)
        if (strpos($ip, ',') !== false) {
            $ip = explode(',', $ip)[0];
        }
        
        $ip = trim($ip);
        
        // For local development, still return the real local IP
        // Don't replace with test IP - return actual device IP
        return $ip;
    }
    
    private function fetchGeolocation($ip) {
        $cachedData = $this->getCachedData($ip);
        if ($cachedData) {
            return $cachedData;
        }
        
        // Check if IP is private/reserved
        if (!$this->isPublicIP($ip)) {
            $ipType = $this->getIPType($ip);
            return [
                'status' => 'success',
                'message' => "Private IP address ({$ipType}) - no public geolocation data available",
                'query' => $ip,
                'country' => 'Private Network',
                'countryCode' => 'PR',
                'region' => $ipType,
                'regionName' => $ipType . ' Network',
                'city' => 'Local Device',
                'district' => null,
                'zip' => null,
                'lat' => null,
                'lon' => null,
                'timezone' => null,
                'offset' => null,
                'isp' => 'Local Network',
                'org' => 'Private',
                'as' => 'Private Network',
                'asname' => 'Private',
                'mobile' => false,
                'proxy' => false,
                'hosting' => false,
                'ip_type' => $ipType
            ];
        }
        
        $url = "http://ip-api.com/json/{$ip}";
        
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_TIMEOUT, 10);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
        curl_setopt($ch, CURLOPT_USERAGENT, 'RSK-World-GeoTracker/1.0');
        
        $response = curl_exec($ch);
        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        curl_close($ch);
        
        if ($httpCode !== 200 || !$response) {
            throw new Exception('Failed to fetch geolocation data');
        }
        
        $data = json_decode($response, true);
        
        if ($data['status'] !== 'success') {
            throw new Exception($data['message'] ?? 'Geolocation lookup failed');
        }
        
        $this->setCachedData($ip, $data);
        return $data;
    }
    
    private function isPublicIP($ip) {
        return filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE) !== false;
    }
    
    private function getIPType($ip) {
        if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) {
            // IPv4 ranges
            if (strpos($ip, '10.') === 0) {
                return 'Private Class A (10.x.x.x)';
            } elseif (strpos($ip, '192.168.') === 0) {
                return 'Private Class C (192.168.x.x)';
            } elseif (strpos($ip, '172.') === 0) {
                $parts = explode('.', $ip);
                if (count($parts) >= 2 && $parts[1] >= 16 && $parts[1] <= 31) {
                    return 'Private Class B (172.16.x.x - 172.31.x.x)';
                }
            } elseif (strpos($ip, '127.') === 0) {
                return 'Loopback (127.x.x.x)';
            } elseif (strpos($ip, '169.254.') === 0) {
                return 'Link-Local (169.254.x.x)';
            }
        } elseif (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) {
            if (strpos($ip, '::1') === 0 || $ip === '::1') {
                return 'IPv6 Loopback';
            } elseif (strpos($ip, 'fc') === 0 || strpos($ip, 'fd') === 0) {
                return 'IPv6 Private';
            }
        }
        return 'Reserved Range';
    }
    
    public function getLocation($ip = null) {
        try {
            $originalIp = $ip;
            $ip = $ip ?: $this->getClientIP();
            
            // Add debug info in development (remove in production)
            $debugInfo = [
                'original_input' => $originalIp,
                'detected_ip' => $ip,
                'client_ip_method' => $originalIp ? 'manual' : 'auto-detect',
                'server_vars' => [
                    'REMOTE_ADDR' => $_SERVER['REMOTE_ADDR'] ?? 'not set',
                    'HTTP_CLIENT_IP' => $_SERVER['HTTP_CLIENT_IP'] ?? 'not set',
                    'HTTP_X_FORWARDED_FOR' => $_SERVER['HTTP_X_FORWARDED_FOR'] ?? 'not set',
                ]
            ];
            
            // Only include debug in development
            $includeDebug = (isset($_GET['debug']) && $_GET['debug'] === 'true');
            
            if (!$this->validateIP($ip)) {
                throw new Exception('Invalid IP address provided: ' . $ip);
            }
            
            $location = $this->fetchGeolocation($ip);
            
            return [
                'success' => true,
                'data' => $location,
                'timestamp' => date('Y-m-d H:i:s'),
                'api_info' => [
                    'provider' => 'ip-api.com',
                    'version' => '1.0',
                    'developer' => 'RSK World',
                    'website' => 'https://rskworld.in',
                    'year' => '2026'
                ]
            ] + ($includeDebug ? ['debug' => $debugInfo] : []);
            
        } catch (Exception $e) {
            return [
                'success' => false,
                'error' => $e->getMessage(),
                'timestamp' => date('Y-m-d H:i:s'),
                'api_info' => [
                    'provider' => 'ip-api.com',
                    'version' => '1.0',
                    'developer' => 'RSK World',
                    'website' => 'https://rskworld.in',
                    'year' => '2026'
                ]
            ];
        }
    }
    
    public function getBulkLocations($ips) {
        $results = [];
        
        foreach ($ips as $ip) {
            $results[$ip] = $this->getLocation($ip);
        }
        
        return [
            'success' => true,
            'data' => $results,
            'timestamp' => date('Y-m-d H:i:s'),
            'api_info' => [
                'provider' => 'ip-api.com',
                'version' => '1.0',
                'developer' => 'RSK World',
                'website' => 'https://rskworld.in',
                'year' => '2026'
            ]
        ];
    }
}

$tracker = new GeolocationTracker();

$method = $_SERVER['REQUEST_METHOD'];
$requestUri = $_SERVER['REQUEST_URI'];
$scriptName = $_SERVER['SCRIPT_NAME'];

// Debug: Show what we're working with
$debug = [
    'request_uri' => $requestUri,
    'script_name' => $scriptName,
    'method' => $method
];

// Simple routing - just handle direct access to index.php
if (strpos($requestUri, 'index.php') !== false || basename($requestUri) === 'geolocation-ip-tracker' || $requestUri === '/') {
    if ($method === 'GET') {
        $ip = $_GET['ip'] ?? null;
        echo json_encode($tracker->getLocation($ip));
    } else {
        http_response_code(405);
        echo json_encode(['error' => 'Method not allowed']);
    }
} elseif (strpos($requestUri, '/bulk') !== false) {
    if ($method === 'POST') {
        $input = json_decode(file_get_contents('php://input'), true);
        $ips = $input['ips'] ?? [];
        echo json_encode($tracker->getBulkLocations($ips));
    } else {
        http_response_code(405);
        echo json_encode(['error' => 'Method not allowed']);
    }
} elseif (strpos($requestUri, '/docs') !== false) {
    if ($method === 'GET') {
        include 'docs.php';
    } else {
        http_response_code(405);
        echo json_encode(['error' => 'Method not allowed']);
    }
} else {
    // For debugging, show what went wrong
    http_response_code(404);
    echo json_encode([
        'error' => 'Endpoint not found',
        'debug' => $debug
    ]);
}
?>
