#!/usr/bin/env python3

"""
Скрипт для тестирования API приложения для безопасности женщин с использованием Python
"""

import json
import requests
import time
import sys
from datetime import datetime, timedelta
from termcolor import colored

BASE_URLS = {
    "gateway": "http://localhost:8000",
    "user": "http://localhost:8001",
    "emergency": "http://localhost:8002",
    "location": "http://localhost:8003",
    "calendar": "http://localhost:8004",
    "notification": "http://localhost:8005"
}

# Класс для тестирования API
class APITester:
    def __init__(self):
        self.token = None
        self.user_id = None
        self.emergency_contact_id = None
        self.alert_id = None
        self.calendar_entry_id = None
        self.device_id = None
    
    def print_section(self, title):
        """Печать заголовка секции"""
        print("\n" + colored("="*50, "yellow"))
        print(colored(f" {title}", "green", attrs=["bold"]))
        print(colored("="*50, "yellow"))
    
    def print_step(self, title):
        """Печать шага тестирования"""
        print(colored(f"\n▶ {title}", "cyan"))
    
    def print_response(self, response, title=None):
        """Печать ответа API"""
        if title:
            print(colored(f"● {title}:", "magenta"))
        
        try:
            if response.status_code >= 400:
                print(colored(f"HTTP Status: {response.status_code}", "red"))
            else:
                print(colored(f"HTTP Status: {response.status_code}", "green"))
            
            json_response = response.json()
            print(json.dumps(json_response, indent=2, ensure_ascii=False))
            return json_response
        except:
            print(colored("Не удалось распарсить JSON ответ", "red"))
            print(response.text)
            return {}
    
    def check_services(self):
        """Проверка доступности всех сервисов"""
        self.print_section("Проверка доступности сервисов")
        
        all_up = True
        
        for service_name, url in BASE_URLS.items():
            print(colored(f"Проверка {service_name.upper()} ({url})...", "cyan"), end=" ")
            
            try:
                # Пробуем разные варианты эндпоинтов health
                health_endpoints = ["/health", "/api/v1/health"]
                service_up = False
                
                for endpoint in health_endpoints:
                    try:
                        response = requests.get(f"{url}{endpoint}", timeout=5)
                        if response.status_code == 200:
                            if "status" in response.json() and "healthy" in response.json()["status"]:
                                service_up = True
                                break
                    except:
                        pass
                
                if service_up:
                    print(colored("OK", "green"))
                else:
                    print(colored("НЕДОСТУПЕН", "red"))
                    all_up = False
            except Exception as e:
                print(colored(f"ОШИБКА: {str(e)}", "red"))
                all_up = False
        
        if not all_up:
            choice = input(colored("Некоторые сервисы недоступны. Продолжить тестирование? (y/n): ", "yellow"))
            if choice.lower() != "y":
                sys.exit(1)
    
    def register_user(self):
        """Регистрация нового пользователя"""
        self.print_step("Регистрация нового пользователя")
        
        data = {
            "username": f"testuser_{int(time.time())}",  # Уникальное имя для каждого запуска
            "email": f"test{int(time.time())}@example.com",
            "password": "Test@1234",
            "full_name": "Тестовый Пользователь",
            "phone_number": "+79001234567"
        }
        
        response = requests.post(f"{BASE_URLS['user']}/api/v1/users/register", json=data)
        user_data = self.print_response(response, "Ответ сервера")
        
        if response.status_code == 201 or response.status_code == 200:
            print(colored("✓ Пользователь успешно зарегистрирован", "green"))
            self.user_id = user_data.get("id")
            return data
        else:
            print(colored("✗ Ошибка при регистрации пользователя", "red"))
            return None
    
    def login_user(self, credentials):
        """Авторизация пользователя"""
        self.print_step("Авторизация пользователя")
        
        data = {
            "username": credentials["username"],
            "password": credentials["password"]
        }
        
        response = requests.post(f"{BASE_URLS['user']}/api/v1/auth/login", json=data)
        login_data = self.print_response(response, "Ответ сервера")
        
        if response.status_code == 200 and "access_token" in login_data:
            self.token = login_data["access_token"]
            print(colored("✓ Успешная авторизация", "green"))
            return True
        else:
            print(colored("✗ Ошибка авторизации", "red"))
            return False
    
    def update_profile(self):
        """Обновление профиля пользователя"""
        self.print_step("Обновление профиля пользователя")
        
        data = {
            "full_name": "Обновленное Имя",
            "phone_number": "+79009876543"
        }
        
        headers = {"Authorization": f"Bearer {self.token}"}
        response = requests.patch(f"{BASE_URLS['user']}/api/v1/users/me", json=data, headers=headers)
        self.print_response(response, "Ответ сервера")
        
        if response.status_code == 200:
            print(colored("✓ Профиль успешно обновлен", "green"))
            return True
        else:
            print(colored("✗ Ошибка при обновлении профиля", "red"))
            return False
    
    def add_emergency_contact(self):
        """Добавление контакта для экстренной связи"""
        self.print_step("Добавление экстренного контакта")
        
        data = {
            "name": "Экстренный Контакт",
            "phone_number": "+79991112233",
            "relationship": "Родственник"
        }
        
        headers = {"Authorization": f"Bearer {self.token}"}
        response = requests.post(f"{BASE_URLS['user']}/api/v1/users/me/emergency-contacts", 
                                json=data, headers=headers)
        contact_data = self.print_response(response, "Ответ сервера")
        
        if response.status_code == 201 or response.status_code == 200:
            self.emergency_contact_id = contact_data.get("id")
            print(colored("✓ Экстренный контакт добавлен", "green"))
            return True
        else:
            print(colored("✗ Ошибка при добавлении контакта", "red"))
            return False
    
    def update_location(self):
        """Обновление местоположения пользователя"""
        self.print_step("Обновление местоположения")
        
        data = {
            "latitude": 55.7558,
            "longitude": 37.6173,
            "accuracy": 10.0
        }
        
        headers = {"Authorization": f"Bearer {self.token}"}
        response = requests.post(f"{BASE_URLS['location']}/api/v1/locations/update", 
                               json=data, headers=headers)
        self.print_response(response, "Ответ сервера")
        
        if response.status_code == 200 or response.status_code == 201:
            print(colored("✓ Местоположение обновлено", "green"))
            return True
        else:
            print(colored("✗ Ошибка при обновлении местоположения", "red"))
            return False
    
    def get_location(self):
        """Получение текущего местоположения"""
        self.print_step("Получение местоположения")
        
        headers = {"Authorization": f"Bearer {self.token}"}
        response = requests.get(f"{BASE_URLS['location']}/api/v1/locations/last", headers=headers)
        self.print_response(response, "Ответ сервера")
        
        if response.status_code == 200:
            print(colored("✓ Местоположение получено", "green"))
            return True
        else:
            print(colored("✗ Ошибка при получении местоположения", "red"))
            return False
    
    def create_emergency_alert(self):
        """Создание экстренного оповещения"""
        self.print_step("Создание экстренного оповещения")
        
        data = {
            "latitude": 55.7558,
            "longitude": 37.6173,
            "alert_type": "SOS",
            "message": "Тестовое экстренное оповещение"
        }
        
        headers = {"Authorization": f"Bearer {self.token}"}
        response = requests.post(f"{BASE_URLS['emergency']}/api/v1/emergency/alerts", 
                               json=data, headers=headers)
        alert_data = self.print_response(response, "Ответ сервера")
        
        if response.status_code == 201 or response.status_code == 200:
            self.alert_id = alert_data.get("id")
            print(colored("✓ Экстренное оповещение создано", "green"))
            return True
        else:
            print(colored("✗ Ошибка при создании оповещения", "red"))
            return False
    
    def get_alerts(self):
        """Получение активных оповещений"""
        self.print_step("Получение активных оповещений")
        
        headers = {"Authorization": f"Bearer {self.token}"}
        response = requests.get(f"{BASE_URLS['emergency']}/api/v1/emergency/alerts/my", headers=headers)
        self.print_response(response, "Ответ сервера")
        
        if response.status_code == 200:
            print(colored("✓ Список оповещений получен", "green"))
            return True
        else:
            print(colored("✗ Ошибка при получении оповещений", "red"))
            return False
    
    def cancel_alert(self):
        """Отмена экстренного оповещения"""
        if not self.alert_id:
            print(colored("⚠ Нет активного оповещения для отмены", "yellow"))
            return False
        
        self.print_step("Отмена экстренного оповещения")
        
        headers = {"Authorization": f"Bearer {self.token}"}
        response = requests.patch(f"{BASE_URLS['emergency']}/api/v1/emergency/alerts/{self.alert_id}/cancel", 
                                headers=headers)
        self.print_response(response, "Ответ сервера")
        
        if response.status_code == 200:
            print(colored("✓ Оповещение отменено", "green"))
            return True
        else:
            print(colored("✗ Ошибка при отмене оповещения", "red"))
            return False
    
    def create_calendar_entry(self):
        """Создание записи в календаре"""
        self.print_step("Создание записи в календаре")
        
        data = {
            "entry_date": datetime.now().strftime("%Y-%m-%d"),
            "cycle_day": 1,
            "symptoms": ["HEADACHE", "FATIGUE"],
            "mood": "NORMAL",
            "notes": "Тестовая запись"
        }
        
        headers = {"Authorization": f"Bearer {self.token}"}
        response = requests.post(f"{BASE_URLS['calendar']}/api/v1/calendar/entries", 
                               json=data, headers=headers)
        entry_data = self.print_response(response, "Ответ сервера")
        
        if response.status_code == 201 or response.status_code == 200:
            self.calendar_entry_id = entry_data.get("id")
            print(colored("✓ Запись в календаре создана", "green"))
            return True
        else:
            print(colored("✗ Ошибка при создании записи в календаре", "red"))
            return False
    
    def get_calendar_entries(self):
        """Получение записей календаря"""
        self.print_step("Получение записей календаря")
        
        start_date = (datetime.now() - timedelta(days=30)).strftime("%Y-%m-%d")
        end_date = (datetime.now() + timedelta(days=30)).strftime("%Y-%m-%d")
        
        headers = {"Authorization": f"Bearer {self.token}"}
        response = requests.get(
            f"{BASE_URLS['calendar']}/api/v1/calendar/entries?start_date={start_date}&end_date={end_date}",
            headers=headers
        )
        self.print_response(response, "Ответ сервера")
        
        if response.status_code == 200:
            print(colored("✓ Записи календаря получены", "green"))
            return True
        else:
            print(colored("✗ Ошибка при получении записей календаря", "red"))
            return False
    
    def register_device(self):
        """Регистрация устройства для уведомлений"""
        self.print_step("Регистрация устройства для уведомлений")
        
        data = {
            "device_token": f"test-token-{int(time.time())}",
            "device_type": "ANDROID",
            "app_version": "1.0.0"
        }
        
        headers = {"Authorization": f"Bearer {self.token}"}
        response = requests.post(f"{BASE_URLS['notification']}/api/v1/notifications/devices", 
                               json=data, headers=headers)
        device_data = self.print_response(response, "Ответ сервера")
        
        if response.status_code == 201 or response.status_code == 200:
            self.device_id = device_data.get("id")
            print(colored("✓ Устройство зарегистрировано", "green"))
            return True
        else:
            print(colored("✗ Ошибка при регистрации устройства", "red"))
            return False
    
    def set_notification_preferences(self):
        """Настройка предпочтений уведомлений"""
        self.print_step("Настройка предпочтений уведомлений")
        
        data = {
            "emergency_alerts": True,
            "nearby_incidents": True,
            "calendar_reminders": True,
            "system_notifications": True
        }
        
        headers = {"Authorization": f"Bearer {self.token}"}
        response = requests.post(f"{BASE_URLS['notification']}/api/v1/notifications/preferences", 
                               json=data, headers=headers)
        self.print_response(response, "Ответ сервера")
        
        if response.status_code == 200 or response.status_code == 201:
            print(colored("✓ Предпочтения уведомлений настроены", "green"))
            return True
        else:
            print(colored("✗ Ошибка при настройке предпочтений", "red"))
            return False
    
    def get_gateway_dashboard(self):
        """Получение данных через API Gateway"""
        self.print_step("Получение данных пользователя через Gateway")
        
        headers = {"Authorization": f"Bearer {self.token}"}
        response = requests.get(f"{BASE_URLS['gateway']}/api/v1/users/dashboard", headers=headers)
        self.print_response(response, "Ответ сервера")
        
        if response.status_code == 200:
            print(colored("✓ Данные получены через Gateway", "green"))
            return True
        else:
            print(colored("✗ Ошибка при получении данных через Gateway", "red"))
            return False
    
    def run_tests(self):
        """Запуск полной серии тестов"""
        self.print_section("НАЧАЛО ТЕСТИРОВАНИЯ API")
        
        # Проверка доступности сервисов
        self.check_services()
        
        # Регистрация и авторизация
        user_data = self.register_user()
        if not user_data:
            print(colored("Критическая ошибка: Не удалось зарегистрировать пользователя", "red"))
            return False
        
        if not self.login_user(user_data):
            print(colored("Критическая ошибка: Не удалось авторизоваться", "red"))
            return False
        
        # Основные тесты
        self.update_profile()
        self.add_emergency_contact()
        self.update_location()
        self.get_location()
        self.create_emergency_alert()
        self.get_alerts()
        self.cancel_alert()
        self.create_calendar_entry()
        self.get_calendar_entries()
        self.register_device()
        self.set_notification_preferences()
        self.get_gateway_dashboard()
        
        self.print_section("ТЕСТИРОВАНИЕ ЗАВЕРШЕНО")
        print(colored("✓ Тесты API выполнены успешно!", "green", attrs=["bold"]))
        return True


if __name__ == "__main__":
    tester = APITester()
    tester.run_tests()