import requests
import hashlib
import json
from .base_plugin import BasePMSPlugin
from datetime import datetime, timedelta
from asgiref.sync import sync_to_async
from touchh.utils.log import CustomLogger
from hotels.models import Hotel, Reservation
from app_settings.models import GlobalHotelSettings
from django.utils import timezone

class RealtyCalendarPlugin(BasePMSPlugin):
    def __init__(self, config):
        super().__init__(config)
        self.public_key = config.public_key
        self.private_key = config.private_key
        self.api_url = config.url.rstrip("/")
        self.logger = CustomLogger(name="RealtyCalendarPlugin", log_level="DEBUG").get_logger()
        if not self.public_key or not self.private_key:
            raise ValueError("Публичный или приватный ключ отсутствует для RealtyCalendar")

    def get_default_parser_settings(self):
        """
        Возвращает настройки по умолчанию для обработки данных.
        """
        return {
            "date_format": "%Y-%m-%dT%H:%M:%S",
            "timezone": "UTC"
        }
    def _get_sorted_keys(self, obj):
        sorted_keys = sorted(obj.keys())
        self.logger.debug(f"Отсортированные ключи: {sorted_keys}")
        return sorted_keys

    def _generate_data_string(self, obj):
        sorted_keys = self._get_sorted_keys(obj)
        string = "".join(f"{key}={obj[key]}" for key in sorted_keys)
        self.logger.debug(f"Сформированная строка данных: {string}")
        return string + self.private_key

    def _generate_md5(self, string):
        md5_hash = hashlib.md5(string.encode("utf-8")).hexdigest()
        self.logger.debug(f"Сформированный MD5-хеш: {md5_hash}")
        return md5_hash

    def _generate_sign(self, data):
        data_string = self._generate_data_string(data)
        self.logger.debug(f"Строка для подписи: {data_string}")
        sign = self._generate_md5(data_string)
        self.logger.debug(f"Подпись: {sign}")
        return sign

    # async def _fetch_data(self):
    #     self.logger.debug("Начало выполнения функции _fetch_data")
    #     base_url = f"{self.api_url}/api/v1/bookings/{self.public_key}/"
    #     headers = {
    #         "Accept": "application/json",
    #         "Content-Type": "application/json",
    #     }

    #     now = datetime.now()
    #     data = {
    #         "begin_date": (now - timedelta(days=7)).strftime("%Y-%m-%d"),
    #         "end_date": now.strftime("%Y-%m-%d"),
    #     }
    #     data["sign"] = self._generate_sign(data)

    #     try:
    #         response = requests.post(url=base_url, headers=headers, json=data)
    #         self.logger.debug(f"Статус ответа: {response.status_code}")

    #         if response.status_code != 200:
    #             self.logger.error(f"Ошибка API: {response.status_code}, {response.text}")
    #             raise ValueError(f"Ошибка API RealtyCalendar: {response.status_code}")

    #         try:
    #             response_data = response.json()
    #             bookings = response_data.get("bookings", [])
    #             # self.logger.debug(f"Полученные данные: {bookings}")

    #             if not isinstance(bookings, list):
    #                 self.logger.error(f"Ожидался список, но получен: {type(bookings)}")
    #                 raise ValueError("Некорректный формат данных для bookings")
    #         except json.JSONDecodeError as e:
    #             self.logger.error(f"Ошибка декодирования JSON: {e}")
    #             raise ValueError("Ответ не является корректным JSON.")
    #         except Exception as e:
    #             self.logger.error(f"Ошибка обработки ответа API: {e}")
    #             raise

    #     except Exception as e:
    #         self.logger.error(f"Ошибка запроса к API RealtyCalendar: {e}")
    #         raise

    #     try:
    #         hotel = await sync_to_async(Hotel.objects.get)(pms=self.pms_config)
    #         hotel_tz = hotel.timezone
    #         self.logger.debug(f"Настройки отеля: {hotel.name}, Timezone: {hotel_tz}")

    #         hotel_settings = await sync_to_async(GlobalHotelSettings.objects.first)()
    #         check_in_time = hotel_settings.check_in_time.strftime("%H:%M:%S") if hotel_settings else "14:00:00"
    #         check_out_time = hotel_settings.check_out_time.strftime("%H:%M:%S") if hotel_settings else "12:00:00"
    #     except Exception as e:
    #         self.logger.error(f"Ошибка получения настроек отеля: {e}")
    #         check_in_time, check_out_time = "14:00:00", "12:00:00"

    #     filtered_data = []
    #     for item in bookings:
    #         try:
    #             if not isinstance(item, dict):
    #                 self.logger.error(f"Некорректный формат элемента: {item}")
    #                 continue

    #             reservation_id = item.get('id')
    #             if not reservation_id:
    #                 self.logger.error(f"ID резервации отсутствует: {item}")
    #                 continue

    #             begin_date = item.get('begin_date')
    #             end_date = item.get('end_date')
    #             if not begin_date or not end_date:
    #                 self.logger.error(f"Отсутствуют даты в записи: {item}")
    #                 continue

    #             checkin = timezone.make_aware(
    #                 datetime.strptime(f"{begin_date} {check_in_time}", "%Y-%m-%d %H:%M:%S")
    #             )
    #             checkout = timezone.make_aware(
    #                 datetime.strptime(f"{end_date} {check_out_time}", "%Y-%m-%d %H:%M:%S")
    #             )

    #             filtered_data.append({
    #                 'reservation_id': reservation_id,
    #                 'checkin': checkin,
    #                 'checkout': checkout,
    #                 'room_number': item.get('apartment_id'),
    #                 'room_type': item.get('notes', 'Описание отсутствует'),
    #                 'status': item.get('status')
    #             })
    #         except Exception as e:
    #             self.logger.error(f"Ошибка обработки элемента: {e}")

    #     # self.logger.debug(f"Отфильтрованные данные: {filtered_data}")
    #     await self._save_to_db(filtered_data)

    async def _fetch_data(self):
        self.logger.debug("Начало выполнения функции _fetch_data")
        base_url = f"{self.api_url}/api/v1/bookings/{self.public_key}/"
        headers = {
            "Accept": "application/json",
            "Content-Type": "application/json",
        }

        now = datetime.now()
        data = {
            "begin_date": (now - timedelta(days=7)).strftime("%Y-%m-%d"),
            "end_date": now.strftime("%Y-%m-%d"),
        }
        data["sign"] = self._generate_sign(data)

        try:
            response = requests.post(url=base_url, headers=headers, json=data)
            self.logger.debug(f"Статус ответа: {response.status_code}")

            if response.status_code != 200:
                self.logger.error(f"Ошибка API: {response.status_code}, {response.text}")
                return {
                    "processed_intervals": 0,
                    "processed_items": 0,
                    "errors": [f"Ошибка API RealtyCalendar: {response.status_code}"]
                }

            response_data = response.json()
            bookings = response_data.get("bookings", [])

            if not isinstance(bookings, list):
                self.logger.error(f"Ожидался список, но получен: {type(bookings)}")
                return {
                    "processed_intervals": 0,
                    "processed_items": 0,
                    "errors": ["Некорректный формат данных для bookings"]
                }

        except json.JSONDecodeError as e:
            self.logger.error(f"Ошибка декодирования JSON: {e}")
            return {
                "processed_intervals": 0,
                "processed_items": 0,
                "errors": ["Ответ не является корректным JSON."]
            }
        except Exception as e:
            self.logger.error(f"Ошибка запроса к API RealtyCalendar: {e}")
            return {
                "processed_intervals": 0,
                "processed_items": 0,
                "errors": [str(e)]
            }

        # Получение настроек отеля
        try:
            hotel = await sync_to_async(Hotel.objects.get)(pms=self.pms_config)
            hotel_tz = hotel.timezone
            self.logger.debug(f"Настройки отеля: {hotel.name}, Timezone: {hotel_tz}")

            hotel_settings = await sync_to_async(GlobalHotelSettings.objects.first)()
            check_in_time = hotel_settings.check_in_time.strftime("%H:%M:%S") if hotel_settings else "14:00:00"
            check_out_time = hotel_settings.check_out_time.strftime("%H:%M:%S") if hotel_settings else "12:00:00"
        except Exception as e:
            self.logger.error(f"Ошибка получения настроек отеля: {e}")
            check_in_time, check_out_time = "14:00:00", "12:00:00"

        # Обработка записей
        processed_items = 0
        errors = []
        filtered_data = []

        for item in bookings:
            try:
                if not isinstance(item, dict):
                    raise ValueError(f"Некорректный формат элемента: {item}")

                reservation_id = item.get('id')
                if not reservation_id:
                    raise ValueError(f"ID резервации отсутствует: {item}")

                begin_date = item.get('begin_date')
                end_date = item.get('end_date')
                if not begin_date or not end_date:
                    raise ValueError(f"Отсутствуют даты в записи: {item}")

                checkin = timezone.make_aware(
                    datetime.strptime(f"{begin_date} {check_in_time}", "%Y-%m-%d %H:%M:%S")
                )
                checkout = timezone.make_aware(
                    datetime.strptime(f"{end_date} {check_out_time}", "%Y-%m-%d %H:%M:%S")
                )

                filtered_data.append({
                    'reservation_id': reservation_id,
                    'checkin': checkin,
                    'checkout': checkout,
                    'room_number': item.get('apartment_id'),
                    'room_type': item.get('notes', 'Описание отсутствует'),
                    'status': item.get('status')
                })
                processed_items += 1
            except Exception as e:
                self.logger.error(f"Ошибка обработки элемента: {e}")
                errors.append(str(e))

        # Сохранение в БД
        try:
            await self._save_to_db(filtered_data)
        except Exception as e:
            self.logger.error(f"Ошибка сохранения данных в БД: {e}")
            errors.append(f"Ошибка сохранения данных в БД: {str(e)}")

        # Формирование отчета
        report = {
            "processed_intervals": 1,  # Пример значения
            "processed_items": processed_items,
            "errors": errors
        }
        self.logger.debug(f"Сформированный отчет: {report}")
        return report


    async def _save_to_db(self, data):
        if not isinstance(data, list):
            self.logger.error(f"Ожидался список записей, но получен {type(data).__name__}")
            return

        for index, item in enumerate(data, start=1):
            try:
                hotel = await sync_to_async(Hotel.objects.get)(pms=self.pms_config)
                reservation_id = item.get('reservation_id')
                if not reservation_id:
                    self.logger.error(f"Пропущена запись {index}: отсутствует 'id'")
                    continue

                existing_reservation = await sync_to_async(Reservation.objects.filter)(reservation_id=reservation_id)
                existing_reservation = await sync_to_async(existing_reservation.first)()

                defaults = {
                    'room_number': item['room_number'],
                    'room_type': item['room_type'],
                    'check_in': item['checkin'],
                    'check_out': item['checkout'],
                    'status': item['status'],
                    'hotel': hotel
                }

                if existing_reservation:
                    await sync_to_async(Reservation.objects.update_or_create)(
                        reservation_id=reservation_id, defaults=defaults
                    )
                    self.logger.debug(f"Резервация {reservation_id} обновлена. ")
                else:
                    await sync_to_async(Reservation.objects.create)(
                        reservation_id=reservation_id, **defaults
                    )
                    self.logger.debug(f"Создана новая резервация {reservation_id}")

            except Exception as e:
                self.logger.error(f"Ошибка при обработке записи {index}: {e}")

    def validate_plugin(self):
        required_methods = ["fetch_data", "get_default_parser_settings", "_fetch_data"]
        for m in required_methods:
            if not hasattr(self, m):
                raise ValueError(f"Плагин {type(self).__name__} не реализует метод {m}.")
        self.logger.debug(f"Плагин {self.__class__.__name__} прошел валидацию.")
        return True
