import tkinter as tk
from tkinter import scrolledtext
import threading
import socket
import re
import requests

# Попытка импорта библиотеки whois (может отсутствовать)
try:
    import whois
    WHOIS_AVAILABLE = True
except ImportError:
    WHOIS_AVAILABLE = False


def is_ip(address: str) -> bool:
    """
    Проверяет, является ли строка IP-адресом (простая проверка формата x.x.x.x).
    """
    pattern = r'^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$'
    return re.match(pattern, address) is not None


def resolve_domain(domain: str) -> str or None:
    """
    Разрешает доменное имя в IP-адрес с помощью системного DNS.
    Возвращает IP-адрес или None в случае ошибки.
    """
    try:
        ip = socket.gethostbyname(domain)
        return ip
    except socket.gaierror:
        return None


def get_geo_info(ip: str) -> dict or None:
    """
    Запрашивает гео-информацию по IP через бесплатный API ip-api.com.
    Возвращает словарь с данными (country, city, isp, timezone, query) или None.
    """
    try:
        # fields – запрашиваем только нужные поля для экономии трафика
        url = f"http://ip-api.com/json/{ip}?fields=status,message,country,city,isp,timezone,query"
        resp = requests.get(url, timeout=10)
        data = resp.json()
        if data.get('status') == 'success':
            return data
        else:
            return None
    except Exception:
        return None


def get_whois_info(domain: str) -> dict or str:
    """
    Получает WHOIS-информацию для домена (регистратор, даты создания и окончания).
    Возвращает словарь с данными либо строку с сообщением об ошибке.
    """
    if not WHOIS_AVAILABLE:
        return "⚠️ Библиотека whois не установлена (pip install python-whois)"

    try:
        w = whois.whois(domain)
        registrar = w.registrar if w.registrar else "Не указан"
        creation_date = w.creation_date
        expiration_date = w.expiration_date

        # Иногда даты возвращаются списком – берём первый элемент
        if isinstance(creation_date, list):
            creation_date = creation_date[0]
        if isinstance(expiration_date, list):
            expiration_date = expiration_date[0]

        return {
            'registrar': registrar,
            'creation_date': str(creation_date) if creation_date else "Нет данных",
            'expiration_date': str(expiration_date) if expiration_date else "Нет данных"
        }
    except Exception as e:
        return f"Ошибка WHOIS: {str(e)}"


class AnalyzerApp:
    """
    Основное окно приложения с «хакерским» интерфейсом.
    """

    def __init__(self, root: tk.Tk):
        self.root = root
        self.root.title("Analyzer")
        self.root.configure(bg="#1e1e1e")

        # Моноширинный шрифт в стиле терминала
        self.font = ("Courier", 10)

        # Поле ввода IP/домена
        self.entry = tk.Entry(
            root,
            bg="#1e1e1e",
            fg="#00ff00",
            insertbackground="#00ff00",
            font=self.font,
            width=50
        )
        self.entry.pack(pady=(15, 5))
        self.entry.focus_set()

        # Кнопка запуска анализа
        self.btn = tk.Button(
            root,
            text="Анализировать",
            command=self.start_analysis,
            bg="#333333",
            fg="#00ff00",
            activebackground="#555555",
            activeforeground="#00ff00",
            font=("Courier", 10, "bold"),
            relief=tk.FLAT,
            bd=2
        )
        self.btn.pack(pady=5)

        # Большое поле вывода с прокруткой
        self.output = scrolledtext.ScrolledText(
            root,
            wrap=tk.WORD,
            bg="#1e1e1e",
            fg="#00ff00",
            font=self.font,
            state=tk.DISABLED,
            width=80,
            height=20
        )
        self.output.pack(padx=10, pady=(5, 15), fill=tk.BOTH, expand=True)

        # Запуск анализа по нажатию Enter
        self.root.bind('<Return>', lambda event: self.start_analysis())

    def update_output(self, text: str) -> None:
        """Безопасное обновление текстового поля (вызывается из основного потока)."""
        self.output.config(state=tk.NORMAL)
        self.output.delete(1.0, tk.END)
        self.output.insert(tk.END, text)
        self.output.config(state=tk.DISABLED)

    def start_analysis(self) -> None:
        """Обработчик нажатия кнопки: запускает анализ в отдельном потоке."""
        target = self.entry.get().strip()
        if not target:
            self.update_output("❌ Введите IP-адрес или домен")
            return

        # Блокируем кнопку на время запросов
        self.btn.config(state=tk.DISABLED, text="Анализ...")
        # Показываем индикатор загрузки
        self.update_output("⏳ Выполняется анализ...")

        # Поток-демон, чтобы не мешал закрытию программы
        thread = threading.Thread(target=self.run_analysis, args=(target,), daemon=True)
        thread.start()

    def run_analysis(self, target: str) -> None:
        """
        Основная логика анализа (выполняется в фоновом потоке).
        Собирает информацию, формирует отчёт и передаёт его в GUI.
        """
        result = ""

        # --- 1. Определение типа ввода и разрешение IP, если домен ---
        if is_ip(target):
            ip = target
            domain = None
            result += f"🌐 Объект: IP {ip}\n\n"
        else:
            domain = target
            result += f"🌐 Объект: домен {domain}\n"
            ip = resolve_domain(domain)
            if ip:
                result += f"   🔗 Разрешённый IP: {ip}\n\n"
            else:
                result += "   ❌ Не удалось разрешить IP-адрес\n\n"

        # --- 2. Геолокация (если известен IP) ---
        geo_data = None
        if ip:
            geo_data = get_geo_info(ip)

        if geo_data:
            result += "📍 Геолокация:\n"
            result += f"   🌍 Страна: {geo_data.get('country', 'N/A')}\n"
            result += f"   🏙️  Город: {geo_data.get('city', 'N/A')}\n"
            result += f"   🏢 Провайдер: {geo_data.get('isp', 'N/A')}\n"
            result += f"   🕒 Часовой пояс: {geo_data.get('timezone', 'N/A')}\n\n"
        else:
            if ip:
                result += "❌ Не удалось получить геоданные\n\n"
            else:
                result += "❌ Нет IP для геолокации\n\n"

        # --- 3. WHOIS (только для доменов) ---
        if domain:
            whois_result = get_whois_info(domain)
            result += "📅 WHOIS информация:\n"
            if isinstance(whois_result, dict):
                result += f"   🏷️  Регистратор: {whois_result['registrar']}\n"
                result += f"   📆 Создан: {whois_result['creation_date']}\n"
                result += f"   ⏳ Истекает: {whois_result['expiration_date']}\n"
            else:
                result += f"   {whois_result}\n"
        else:
            result += "📅 WHOIS информация недоступна (не домен)\n"

        result += "\n🏁 Анализ завершён."

        # Передаём результат в основной поток для обновления GUI
        self.root.after(0, self.finalize_analysis, result)

    def finalize_analysis(self, result: str) -> None:
        """Восстанавливает интерфейс после завершения фонового анализа."""
        self.update_output(result)
        self.btn.config(state=tk.NORMAL, text="Анализировать")


if __name__ == "__main__":
    root = tk.Tk()
    app = AnalyzerApp(root)
    root.mainloop()