import sys
import os
import pytest
from flask import Flask
from flask_httpauth import HTTPBasicAuth
import base64
from redis import from_url, ConnectionPool, Redis
from flask_limiter import Limiter
from flask_limiter.util import get_remote_address
from unittest.mock import patch, Mock

sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '../app')))
from routes import setup_routes

auth = HTTPBasicAuth()

# Force configuration to use fallback values

class TestConfig():
  SECRET_KEY = '28c93e98b2a87e47db16372bdb6e7593fb1addf9ccc10eae562827a7358cab3b'

REDIS_URL="redis://localhost:6379/0"
RATE_LIMITS = ["200 per day", "50 per hour"]

def setup_redis(app):
  pool = ConnectionPool.from_url(REDIS_URL)
  redis_connection = Redis(connection_pool=pool)
  redis_connection.ping()
  app.logger.info("Connected to Redis")
  # Return the redis_connection to be used elsewhere
  return redis_connection

def setup_limiter(app):

  # Rate limiter setup
  limiter = Limiter(
  key_func=get_remote_address,
  app=app,
  storage_uri=REDIS_URL,
  default_limits=RATE_LIMITS
  )

  return limiter

@pytest.fixture
def app():
    app = Flask(__name__)
    redis_connection = setup_redis(app)
    app.config.from_object(TestConfig)
    setup_routes(setup_limiter(app), app, redis_connection)
    return app

@pytest.fixture
def client(app):
    return app.test_client()

@pytest.fixture
def auth_headers():
    password = '4acG2wHmp1-B'
    credentials = f"anon:{password}"
    encoded_credentials = base64.b64encode(credentials.encode()).decode('utf-8')
    headers = {
        'Authorization': f'Basic {encoded_credentials}'
    }
    return headers

def mock_subprocess_run(*args, **kwargs):
    """Mock function to simulate subprocess.run behavior."""
    class MockCompletedProcess:
        def __init__(self, returncode=0, stdout='', stderr=''):
            self.returncode = returncode
            self.stdout = stdout
            self.stderr = stderr

    if 'ping' in args[0]:
        if '192.168.0.0' in args[0]:
            # Simulate unreachable IP
            return MockCompletedProcess(returncode=1, stderr='Unreachable')
        else:
            # Simulate reachable IP
            return MockCompletedProcess(returncode=0, stdout='Ping successful')
    return MockCompletedProcess()

def test_wol_valid_device(client, auth_headers):
  with patch.dict(os.environ, {'LAPTOP_MAC': '00:00:00:00:00:00', 'LAPTOP_IP': '192.168.0.1'}):
      with patch('subprocess.run', mock_subprocess_run):
        response = client.get('/wol/laptop?key=28c93e98b2a87e47db16372bdb6e7593fb1addf9ccc10eae562827a7358cab3b', headers=auth_headers)
        assert response.status_code == 200

def test_unauthorized_wol(client):
    response = client.get('/wol/device1?key=wrongkey')
    assert response.status_code == 401

def test_invalid_device(client, auth_headers):
    response = client.get('/wol/invalid_device?key=28c93e98b2a87e47db16372bdb6e7593fb1addf9ccc10eae562827a7358cab3b', headers=auth_headers)
    assert response.status_code == 400

def test_redis_status(client, auth_headers):
    response = client.get('/redis_status', headers=auth_headers)
    assert response.status_code == 200

def test_reset_limiter(client, auth_headers):
    response = client.get('/reset_limiter?key=28c93e98b2a87e47db16372bdb6e7593fb1addf9ccc10eae562827a7358cab3b', headers=auth_headers)
    assert response.status_code == 200
