import json
import logging
from django.core.exceptions import ImproperlyConfigured
from .models import APISettings, Client, Invoice
import requests

logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)
if not logger.handlers:
    console_handler = logging.StreamHandler()
    console_handler.setLevel(logging.DEBUG)
    formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
    console_handler.setFormatter(formatter)
    logger.addHandler(console_handler)


class APIClient:
    """
    Класс для подключения к API и получения данных.
    Данные API_URL и API_KEY берутся из модели APISettings.
    """
    def __init__(self):
        self.settings = APISettings.objects.first()
        if not self.settings:
            logger.error("Настройки API не сконфигурированы. Заполните модель APISettings.")
            raise ImproperlyConfigured("Настройки API не сконфигурированы.")
        self.api_url = self.settings.api_url.rstrip("/")
        self.api_key = self.settings.api_key
        self.headers = {"X-API-Key": self.api_key}
        logger.debug(f"APIClient инициализирован с базовым URL: {self.api_url}")

    def get_clients(self):
        url = f"{self.api_url}/api/clients"
        logger.debug(f"Запрос клиентов по адресу: {url} с заголовками: {self.headers}")
        try:
            response = requests.get(url, headers=self.headers, timeout=10)
            response.raise_for_status()
            data = response.json()
            logger.debug("Запрос клиентов успешно выполнен. Данные получены.")
            return data
        except requests.exceptions.RequestException as e:
            logger.error(f"Ошибка при запросе клиентов: {e}")
            return None

    def get_invoices(self):
        url = f"{self.api_url}/api/invoices"
        logger.debug(f"Запрос счетов по адресу: {url} с заголовками: {self.headers}")
        try:
            response = requests.get(url, headers=self.headers, timeout=10)
            response.raise_for_status()
            data = response.json()
            logger.debug("Запрос счетов успешно выполнен. Данные получены.")
            return data
        except requests.exceptions.RequestException as e:
            logger.error(f"Ошибка при запросе счетов: {e}")
            return None


class API_SYNC:
    """
    Класс для импорта и обновления данных из API.
    Методы sync_clients и sync_invoices обновляют существующие записи или создают новые.
    """
    def __init__(self):
        self.logger = logger

    def sync_clients(self):
        api_client = APIClient()
        data = api_client.get_clients()
        new_or_updated = 0

        if isinstance(data, dict):
            clients_list = data.get("member", [])
            self.logger.debug(f"Извлечен список клиентов из ключа 'member', найдено записей: {len(clients_list)}")
        elif isinstance(data, list):
            clients_list = data
            self.logger.debug(f"Получен список клиентов (list), количество записей: {len(clients_list)}")
        else:
            self.logger.error("Неожиданный формат данных клиентов от API: %s", type(data))
            return new_or_updated

        for index, item in enumerate(clients_list, start=1):
            self.logger.debug(f"Обработка записи клиента {index}: {item}")
            if isinstance(item, str):
                try:
                    item = json.loads(item)
                    self.logger.debug(f"Запись клиента {index} успешно преобразована из строки в словарь.")
                except Exception as e:
                    self.logger.error("Невозможно преобразовать запись клиента %s в словарь: %s; ошибка: %s", index, item, e)
                    continue

            if isinstance(item, dict):
                club_card_number = item.get("club_card_num")
                if not club_card_number:
                    self.logger.warning("Запись клиента %s пропущена: отсутствует club_card_num. Запись: %s", index, item)
                    continue

                defaults = {
                    'name': item.get("name"),
                }

                telegram_id = item.get("telegram_id")
                if telegram_id:
                    defaults['telegram_id'] = telegram_id  # Обновим только если значение есть

                obj, created = Client.objects.update_or_create(
                    club_card_number=club_card_number,
                    defaults=defaults
                )

                new_or_updated += 1
                if created:
                    self.logger.info("Запись клиента %s создана: club_card_num %s.", index, club_card_number)
                else:
                    self.logger.info("Запись клиента %s обновлена: club_card_num %s.", index, club_card_number)
            else:
                self.logger.error("Запись клиента %s имеет неожиданный тип: %s. Значение: %s", index, type(item), item)
        return new_or_updated


    def sync_invoices(self):
        api_client = APIClient()
        data = api_client.get_invoices()
        new_or_updated = 0

        if isinstance(data, dict):
            invoices_list = data.get("member", [])
            self.logger.debug(f"Извлечен список счетов из ключа 'member', найдено записей: {len(invoices_list)}")
        elif isinstance(data, list):
            invoices_list = data
            self.logger.debug(f"Получен список счетов (list), количество записей: {len(invoices_list)}")
        else:
            self.logger.error("Неожиданный формат данных счетов от API: %s", type(data))
            return new_or_updated

        for index, invoice in enumerate(invoices_list, start=1):
            self.logger.debug(f"Обработка счета {index}: {invoice}")
            if isinstance(invoice, str):
                try:
                    invoice = json.loads(invoice)
                    self.logger.debug(f"Счет {index} успешно преобразован из строки в словарь.")
                except Exception as e:
                    self.logger.error("Невозможно преобразовать счет %s в словарь: %s; ошибка: %s", index, invoice, e)
                    continue
            if not isinstance(invoice, dict):
                self.logger.error("Счет %s имеет неожиданный тип: %s", index, type(invoice))
                continue

            api_id = invoice.get("@id")
            if not api_id:
                self.logger.warning("Счет %s пропущен: отсутствует '@id'.", index)
                continue

            # Извлекаем данные клиента из вложенного объекта
            client_data = invoice.get("client", {})
            client_name = client_data.get("name")
            client_club_card_number = client_data.get("club_card_num")

            # Приводим даты (при необходимости, можно использовать парсинг)
            created_at = invoice.get("created_at")
            closed_at = invoice.get("closed_at")
            if closed_at in [None, "N/A"]:
                closed_at = None

            defaults = {
                'invoice_type': invoice.get("@type"),
                'created_at': created_at,
                'closed_at': closed_at,
                'ext_id': invoice.get("ext_id"),
                'ext_type': invoice.get("ext_type"),
                'client_name': client_name,
                'client_club_card_number': client_club_card_number,
                'sum': invoice.get("sum"),
                'company_number': invoice.get("comp_num"),
                'bonus': invoice.get("bonus"),
                'start_bonus': invoice.get("start_bonus"),
                'deposit_sum': invoice.get("deposit_sum"),
                'notes': invoice.get("notes"),
            }

            obj, created = Invoice.objects.update_or_create(
                api_id=api_id,
                defaults=defaults
            )
            new_or_updated += 1
            if created:
                self.logger.info("Счет %s создан: api_id=%s", index, api_id)
            else:
                self.logger.info("Счет %s обновлен: api_id=%s", index, api_id)
        return new_or_updated
