// location_interface.h - Location interface for Lua sandbox
// Milestone 14: Location access with privacy controls and precision levels

#pragma once

#include <string>
#include <memory>
#include <functional>
#include <mutex>
#include <atomic>
#include <vector>
#include <unordered_map>
#include <chrono>

struct lua_State;

namespace mosis {

struct Position {
    double latitude = 0.0;
    double longitude = 0.0;
    double accuracy = 0.0;         // meters
    double altitude = 0.0;         // meters (optional)
    double altitude_accuracy = 0.0; // meters (optional)
    double heading = 0.0;          // degrees (optional)
    double speed = 0.0;            // m/s (optional)
    int64_t timestamp = 0;         // milliseconds since epoch
};

struct LocationOptions {
    bool enable_high_accuracy = false;
    int timeout_ms = 30000;        // max time to wait
    int max_age_ms = 0;            // accept cached position this old
};

enum class LocationError {
    None,
    PermissionDenied,
    PositionUnavailable,
    Timeout,
    RateLimited,
    WatchLimitReached
};

class LocationWatch {
public:
    using PositionCallback = std::function<void(const Position&)>;
    using ErrorCallback = std::function<void(LocationError, const std::string&)>;

    LocationWatch(int id, const LocationOptions& options);
    ~LocationWatch();

    int GetId() const { return m_id; }
    bool IsActive() const { return m_active; }

    void Start();
    void Stop();

    void SetOnPosition(PositionCallback cb) { m_on_position = std::move(cb); }
    void SetOnError(ErrorCallback cb) { m_on_error = std::move(cb); }

    // For mock mode - simulate position update
    void SimulatePosition(const Position& pos);
    void SimulateError(LocationError error, const std::string& message);

private:
    int m_id;
    LocationOptions m_options;
    std::atomic<bool> m_active{false};
    PositionCallback m_on_position;
    ErrorCallback m_on_error;
    mutable std::mutex m_mutex;
};

class LocationInterface {
public:
    LocationInterface(const std::string& app_id);
    ~LocationInterface();

    // Check if app has location permission
    bool HasFinePermission() const { return m_has_fine_permission; }
    bool HasCoarsePermission() const { return m_has_coarse_permission; }
    void SetFinePermission(bool granted) { m_has_fine_permission = granted; }
    void SetCoarsePermission(bool granted) { m_has_coarse_permission = granted; }

    // Get current position (one-shot)
    // Returns true if request started, false on error
    bool GetCurrentPosition(
        const LocationOptions& options,
        std::function<void(const Position&)> success,
        std::function<void(LocationError, const std::string&)> error,
        std::string& out_error
    );

    // Watch position (continuous)
    // Returns watch on success, nullptr on failure
    std::shared_ptr<LocationWatch> WatchPosition(
        const LocationOptions& options,
        std::string& error
    );

    // Stop a specific watch
    void ClearWatch(int watch_id);

    // Stop all watches for this app
    void ClearAllWatches();

    // Get active watch count
    size_t GetActiveWatchCount() const;

    // Cleanup on app stop
    void Shutdown();

    // For testing
    void SetMockMode(bool enabled) { m_mock_mode = enabled; }
    bool IsMockMode() const { return m_mock_mode; }

    // Mock mode: set the position to return
    void SetMockPosition(const Position& pos) { m_mock_position = pos; }

    // Get watch by ID
    std::shared_ptr<LocationWatch> GetWatch(int id);

    // For rate limiting - check and consume
    bool CheckRateLimit();

private:
    std::string m_app_id;
    std::unordered_map<int, std::shared_ptr<LocationWatch>> m_watches;
    mutable std::mutex m_mutex;
    bool m_mock_mode = true;
    bool m_has_fine_permission = false;
    bool m_has_coarse_permission = false;
    Position m_mock_position;
    int m_next_watch_id = 1;
    std::chrono::steady_clock::time_point m_last_request_time;
    bool m_first_request = true;

    static constexpr int MAX_WATCHES = 5;
    static constexpr int RATE_LIMIT_MS = 1000;  // 1 request per second
    static constexpr double COARSE_ACCURACY_M = 1000.0;  // 1km for coarse

    // Apply precision reduction for coarse permission
    Position ApplyPrecision(const Position& pos) const;

    void CleanupStoppedWatches();
};

// Register location.* APIs as globals
void RegisterLocationAPI(lua_State* L, LocationInterface* location);

} // namespace mosis
