from __future__ import annotations

import json
import platform
from typing import Any, Dict
from urllib.parse import urljoin

from PyQt6.QtCore import Qt
from PyQt6.QtGui import QColor
from PyQt6.QtWidgets import (
    QDialog,
    QFormLayout,
    QFrame,
    QHBoxLayout,
    QLabel,
    QLineEdit,
    QPushButton,
    QVBoxLayout,
)

from core.config import APP_THEMES
from core.tenant_manager import TenantManager

API_LOGIN_URL = "https://app.golder.biz/api/login.php"
OFFLINE_TRIGGER_USERNAME = "ofline_mode"


class TenantLoginDialog(QDialog):
    def __init__(self, tenant_manager: TenantManager, lang: dict = None, parent=None) -> None:
        super().__init__(parent)
        self.tenant_manager = tenant_manager
        self.lang = lang or {}

        self.setWindowTitle(self.lang.get("tenant_login_title", "Golder License Login"))
        self.setModal(True)
        self.setMinimumWidth(540)
        self.setWindowFlag(Qt.WindowType.WindowContextHelpButtonHint, False)

        self._build_ui()
        self._apply_styles()

    def _build_ui(self) -> None:
        root = QVBoxLayout(self)
        root.setContentsMargins(20, 20, 20, 20)
        root.setSpacing(0)

        card = QFrame()
        card.setObjectName("card")
        card_layout = QVBoxLayout(card)
        card_layout.setContentsMargins(24, 24, 24, 24)
        card_layout.setSpacing(14)

        title = QLabel(self.lang.get("tenant_login_title", "Golder License Login"))
        title.setObjectName("title")

        subtitle = QLabel(
            self.lang.get(
                "tenant_login_subtitle",
                "Enter your license username and password to continue.",
            )
        )
        subtitle.setWordWrap(True)
        subtitle.setObjectName("subtitle")

        form = QFormLayout()
        form.setLabelAlignment(Qt.AlignmentFlag.AlignLeft)
        form.setFormAlignment(Qt.AlignmentFlag.AlignTop)
        form.setHorizontalSpacing(12)
        form.setVerticalSpacing(10)

        self.username_input = QLineEdit()
        self.username_input.setPlaceholderText(self.lang.get("username_placeholder", "Username"))
        self.username_input.setClearButtonEnabled(True)
        self.username_input.returnPressed.connect(self._attempt_login)

        self.password_input = QLineEdit()
        self.password_input.setPlaceholderText(self.lang.get("password", "Password"))
        self.password_input.setEchoMode(QLineEdit.EchoMode.Password)
        self.password_input.returnPressed.connect(self._attempt_login)

        form.addRow(self.lang.get("user", "User"), self.username_input)
        form.addRow(self.lang.get("password", "Password"), self.password_input)

        self.status_label = QLabel("")
        self.status_label.setWordWrap(True)
        self.status_label.setObjectName("status")
        self.status_label.setVisible(False)

        self.cancel_button = QPushButton(self.lang.get("cancel", "Cancel"))
        self.cancel_button.clicked.connect(self.reject)

        self.retry_button = QPushButton(self.lang.get("connect", "Connect"))
        self.retry_button.setObjectName("primaryButton")
        self.retry_button.setDefault(True)
        self.retry_button.clicked.connect(self._attempt_login)

        button_row = QHBoxLayout()
        button_row.addStretch()
        button_row.addWidget(self.cancel_button)
        button_row.addWidget(self.retry_button)

        card_layout.addWidget(title)
        card_layout.addWidget(subtitle)
        card_layout.addLayout(form)
        card_layout.addWidget(self.status_label)
        card_layout.addLayout(button_row)

        root.addWidget(card)

    def _apply_styles(self) -> None:
        colors = APP_THEMES.get("Green Harmony", {})
        primary = colors.get("primary", "#285430")
        secondary = colors.get("secondary", "#5F8D4E")
        background = colors.get("background", "#F1F8E9")
        text_dark = colors.get("text_dark", "#000000")
        text_light = colors.get("text_light", "#FFFFFF")
        danger = colors.get("danger", "#D32F2F")

        bg_qcolor = QColor(background)
        card_bg = bg_qcolor.lighter(105).name() if bg_qcolor.lightness() < 235 else "#FFFFFF"
        border = bg_qcolor.darker(110).name() if bg_qcolor.lightness() > 110 else "#B7C6AE"
        input_bg = bg_qcolor.lighter(108).name() if bg_qcolor.lightness() < 245 else "#FFFFFF"

        self.setStyleSheet(
            f"""
            QDialog {{
                background-color: {background};
                color: {text_dark};
            }}
            QFrame#card {{
                background-color: {card_bg};
                border: 1px solid {border};
                border-radius: 12px;
            }}
            QLabel#title {{
                font-size: 22px;
                font-weight: 700;
                color: {primary};
            }}
            QLabel#subtitle {{
                color: {text_dark};
                font-size: 12px;
            }}
            QLabel#status {{
                border-radius: 8px;
                padding: 10px;
                background: #FBE9E7;
                color: #7F1D1D;
                border: 1px solid {danger};
                font-size: 12px;
            }}
            QLineEdit {{
                border: 1px solid {border};
                border-radius: 6px;
                padding: 8px 10px;
                background: {input_bg};
                color: #111111;
                min-height: 18px;
            }}
            QLineEdit::placeholder {{
                color: #4B5563;
            }}
            QLineEdit:focus {{
                border: 2px solid {secondary};
            }}
            QPushButton {{
                border: 1px solid {border};
                border-radius: 6px;
                padding: 8px 14px;
                background: {card_bg};
                color: {text_dark};
                font-weight: 600;
                min-width: 120px;
            }}
            QPushButton:hover {{
                border: 1px solid {secondary};
            }}
            QPushButton#primaryButton {{
                background: {primary};
                border: 1px solid {primary};
                color: {text_light};
            }}
            QPushButton#primaryButton:hover {{
                background: {secondary};
                border: 1px solid {secondary};
            }}
            QPushButton#primaryButton:disabled {{
                background: #9FB69B;
                border: 1px solid #9FB69B;
            }}
            """
        )

    def _set_status(self, message: str) -> None:
        self.status_label.setText(message)
        self.status_label.setVisible(bool(message))

    def _set_loading(self, loading: bool) -> None:
        self.retry_button.setDisabled(loading)
        self.cancel_button.setDisabled(loading)
        self.username_input.setDisabled(loading)
        self.password_input.setDisabled(loading)
        self.retry_button.setText(
            self.lang.get("connecting", "Connecting...") if loading else self.lang.get("connect", "Connect")
        )

    def _attempt_offline_login(self, offline_password: str) -> None:
        normalized_password = str(offline_password or "").strip()
        if not normalized_password:
            self._set_status("Lutfen kullanici adi ve sifre alanlarini doldurun.")
            return

        self._set_status("")
        try:
            self.tenant_manager.activate_offline_mode(normalized_password)
        except Exception as exc:
            self._set_status(f"Giris basarisiz: {exc}")
            return
        self.accept()

    def _attempt_login(self) -> None:
        username = self.username_input.text().strip()
        password = self.password_input.text()

        if not username or not password:
            self._set_status("Lutfen kullanici adi ve sifre alanlarini doldurun.")
            return

        if username.lower() == OFFLINE_TRIGGER_USERNAME:
            self._attempt_offline_login(password)
            return

        try:
            import requests
        except Exception:
            self._set_status("`requests` kutuphanesi bulunamadi. Lutfen kurun: pip install requests")
            return

        hw_id = self.tenant_manager.get_hardware_id()
        device_name = platform.node().strip() or "PC"
        request_payload = {
            "username": username,
            "password": password,
            "hardware_id": hw_id,
            "device_name": device_name,
        }

        self._set_status("")
        self._set_loading(True)
        try:
            response = requests.post(
                API_LOGIN_URL,
                data=request_payload,
                timeout=15,
                allow_redirects=False,
            )
            if response.is_redirect or response.status_code in {301, 302, 303, 307, 308}:
                redirected_url = response.headers.get("Location", "").strip()
                if not redirected_url:
                    raise RuntimeError("API yonlendirme adresi alinamadi.")
                redirected_url = urljoin(API_LOGIN_URL, redirected_url)
                response = requests.post(
                    redirected_url,
                    data=request_payload,
                    timeout=15,
                    allow_redirects=False,
                )
            payload = self._parse_api_response(response)
        except Exception as exc:
            self._set_status(f"Sunucuya baglanilamadi: {exc}")
            return
        finally:
            self._set_loading(False)

        if not isinstance(payload, dict):
            self._set_status("Beklenmeyen sunucu yaniti alindi.")
            return

        if payload.get("status") != "success":
            message = str(payload.get("message") or "Giris basarisiz.")
            self._set_status(message)
            return

        data = payload.get("data")
        if not isinstance(data, (dict, list)):
            self._set_status("Sunucudan lisans verisi alinamadi.")
            return

        normalized = self._normalize_api_data(data, login_username=username)

        try:
            self.tenant_manager.save_from_api(normalized)
        except Exception as exc:
            self._set_status(f"Lisans dogrulamasi basarisiz: {exc}")
            return
        self.accept()

    def _parse_api_response(self, response: Any) -> Dict[str, Any]:
        try:
            payload = response.json()
        except ValueError:
            payload = None

        if response.ok:
            if isinstance(payload, dict):
                return payload
            raise RuntimeError("Sunucudan gecersiz JSON yaniti alindi.")

        if isinstance(payload, dict):
            message = str(payload.get("message") or payload.get("code") or "").strip()
            if message:
                raise RuntimeError(message)

        raw_text = ""
        try:
            raw_text = response.text.strip()
        except Exception:
            raw_text = ""

        if raw_text:
            try:
                decoded = json.loads(raw_text)
            except ValueError:
                decoded = None
            if isinstance(decoded, dict):
                message = str(decoded.get("message") or decoded.get("code") or "").strip()
                if message:
                    raise RuntimeError(message)

        response.raise_for_status()
        raise RuntimeError("Sunucu beklenmeyen bir hata dondurdu.")

    def _normalize_api_data(self, data: Any, login_username: str = "") -> Dict[str, Any]:
        source: Dict[str, Any] = data if isinstance(data, dict) else {"customers": data}
        customer = self._extract_customer_row(source, login_username)

        db_host = str(
            source.get("db_host")
            or source.get("host")
            or source.get("mysql_host")
            or self.tenant_manager.DEFAULT_VPS_HOST
        ).strip()
        db_name = str(
            source.get("db_name")
            or source.get("mysql_db_name")
            or customer.get("db_name")
            or customer.get("mysql_db_name")
            or ""
        ).strip()
        db_user = str(
            source.get("db_user")
            or source.get("mysql_db_user")
            or customer.get("db_user")
            or customer.get("mysql_db_user")
            or ""
        ).strip()
        db_pass = str(
            source.get("db_pass")
            or source.get("mysql_db_pass")
            or customer.get("db_pass")
            or customer.get("mysql_db_pass")
            or ""
        )

        plan_type = self.tenant_manager._normalize_plan_type(
            customer.get("plan_type") or source.get("plan_type") or "A-SOLO"
        )
        username = str(
            customer.get("username")
            or customer.get("customer_username")
            or source.get("username")
            or source.get("customer_username")
            or login_username
            or ""
        ).strip()
        email = str(customer.get("email") or source.get("email") or source.get("mail") or "").strip()
        phone = str(
            customer.get("phone_number")
            or customer.get("phone")
            or source.get("phone_number")
            or source.get("phone")
            or source.get("phone_no")
            or ""
        ).strip()
        desktop_expiry = str(
            customer.get("desktop_expiry_date")
            or source.get("desktop_expiry_date")
            or customer.get("expiry_date")
            or source.get("expiry_date")
            or source.get("license_expiry_date")
            or source.get("plan_expiry_date")
            or ""
        ).strip()
        sync_expiry = str(
            customer.get("sync_expiry_date")
            or source.get("sync_expiry_date")
            or ""
        ).strip()
        try:
            max_devices = int(customer.get("max_devices") or source.get("max_devices") or 1)
        except (TypeError, ValueError):
            max_devices = 1
        try:
            max_pc_devices = int(
                customer.get("max_pc_devices")
                or source.get("max_pc_devices")
                or max_devices
                or 1
            )
        except (TypeError, ValueError):
            max_pc_devices = max(1, max_devices)
        try:
            max_web_sessions = int(customer.get("max_web_sessions") or source.get("max_web_sessions") or 0)
        except (TypeError, ValueError):
            max_web_sessions = 0
        try:
            is_ai_enabled = int(customer.get("is_ai_enabled") or source.get("is_ai_enabled") or 0)
        except (TypeError, ValueError):
            is_ai_enabled = 0
        sync_status = str(
            source.get("sync_status")
            or customer.get("sync_status")
            or ""
        ).strip().lower()
        return {
            "plan_type": plan_type,
            "db_host": db_host,
            "db_name": db_name,
            "db_user": db_user,
            "db_pass": db_pass,
            "max_devices": max(1, max_devices),
            "max_pc_devices": max(1, max_pc_devices),
            "max_web_sessions": max(0, max_web_sessions),
            "is_ai_enabled": max(0, is_ai_enabled),
            "customer_username": username,
            "customer_email": email,
            "customer_phone": phone,
            "desktop_expiry_date": desktop_expiry,
            "sync_expiry_date": sync_expiry,
            "sync_status": sync_status,
            "web_mobile_enabled": source.get("web_mobile_enabled", customer.get("web_mobile_enabled")),
            "license_expiry_date": desktop_expiry,
            "expiry_date": desktop_expiry,
            "license_payload": str(source.get("license_payload") or ""),
            "license_signature": str(source.get("license_signature") or ""),
            "license_key_id": str(source.get("license_key_id") or ""),
            "license_algorithm": str(source.get("license_algorithm") or "Ed25519"),
            "license_public_key": str(source.get("license_public_key") or ""),
            "api_token": str(source.get("api_token") or ""),
            "api_token_expires_at": str(source.get("api_token_expires_at") or ""),
            "customer_id": source.get("customer_id") or customer.get("customer_id") or 0,
        }

    def _extract_customer_row(self, source: Dict[str, Any], login_username: str) -> Dict[str, Any]:
        if isinstance(source.get("customer"), dict):
            return dict(source.get("customer") or {})
        customers = source.get("customers")
        if isinstance(customers, list):
            picked = self._pick_customer_from_list(customers, source, login_username)
            if picked:
                return picked
        marker_keys = {"username", "email", "phone_number", "mysql_db_name", "mysql_db_user"}
        if any(key in source for key in marker_keys):
            return dict(source)
        return {}

    def _pick_customer_from_list(
        self,
        customers: list[Any],
        source: Dict[str, Any],
        login_username: str,
    ) -> Dict[str, Any]:
        wanted_user = str(login_username or "").strip().lower()
        wanted_db_name = str(source.get("db_name") or source.get("mysql_db_name") or "").strip().lower()
        wanted_db_user = str(source.get("db_user") or source.get("mysql_db_user") or "").strip().lower()

        best_score = -1
        best_row: Dict[str, Any] = {}
        for row in customers:
            if not isinstance(row, dict):
                continue
            row_user = str(row.get("username") or "").strip().lower()
            row_db_name = str(row.get("mysql_db_name") or row.get("db_name") or "").strip().lower()
            row_db_user = str(row.get("mysql_db_user") or row.get("db_user") or "").strip().lower()

            score = 0
            if wanted_user and row_user == wanted_user:
                score += 3
            if wanted_db_name and row_db_name == wanted_db_name:
                score += 2
            if wanted_db_user and row_db_user == wanted_db_user:
                score += 2
            if str(row.get("last_pc_login_date") or "").strip():
                score += 1

            if score > best_score:
                best_score = score
                best_row = row
        return dict(best_row) if best_row else {}




