import requests
import json
from datetime import datetime, timedelta, timezone

from asgiref.sync import sync_to_async
from hotels.models import Reservation, Hotel
from .base_plugin import BasePMSPlugin
from pms_integration.models import PMSConfiguration

class Shelter(BasePMSPlugin):
    """
    Плагин для интеграции с Shelter PMS.
    """
    def __init__(self, pms_config):
        super().__init__(pms_config)
        self.api_url = pms_config.url
        self.token = pms_config.token
        self.pagination_count = 50
    def get_default_parser_settings(self):
            """
            Возвращает настройки по умолчанию для разбора данных PMS Shelter.
            """
            return {
                "fields_mapping": {
                    "reservation_id": "id",
                    "hotel_id": "hotelId",
                    "hotel_name": "hotelName",
                    "check_in": "from",
                    "check_out": "until",
                    "reservation_date": "date",
                    "room_type_id": "roomTypeId",
                    "room_id": "roomId",
                    "room_number": "roomNumber",
                    "room_type_name": "roomTypeName",
                    "check_in_status": "checkInStatus",
                    "is_annul": "isAnnul",
                    "reservation_price": "reservationPrice",
                    "discount": "discount",

                },
                "date_format": "%Y-%m-%dT%H:%M:%S",
                "timezone": "UTC",
            }
                
    async def _get_last_saved_date(self):
        """
        Получает дату последнего сохраненного бронирования для отеля.
        """
        try:
            last_reservation = await sync_to_async(
                Reservation.objects.filter(hotel__pms=self.pms_config).order_by('-check_in').first
            )()
            return last_reservation.check_in if last_reservation else None
        except Exception as e:
            print(f"[ERROR] Ошибка получения последнего сохраненного бронирования: {e}")
            return None
    async def _fetch_data(self):
        """
        Получает данные о бронированиях из PMS.
        Данные обрабатываются по временным промежуткам и сразу записываются в БД.
        Возвращает отчёт о проделанной работе.
        """
        now = datetime.utcnow().replace(tzinfo=timezone.utc)
        start_date = await self._get_last_saved_date() or (now - timedelta(days=90))
        end_date = now + timedelta(days=30)

        headers = {
            'accept': 'text/plain',
            'Authorization': f'Bearer {self.token}',
            'Content-Type': 'application/json',
        }

        print(f"[DEBUG] Fetching data from {start_date} to {end_date}")

        # Результаты выполнения
        report = {
            "processed_intervals": 0,
            "processed_items": 0,
            "errors": [],
        }

        # Разделение на временные интервалы
        interval_days = 5  # Например, каждые 5 дней
        current_start_date = start_date

        while current_start_date < end_date:
            current_end_date = min(current_start_date + timedelta(days=interval_days), end_date)

            # Формирование payload
            payload = {
                "from": current_start_date.strftime('%Y-%m-%dT%H:%M:%SZ'),
                "until": current_end_date.strftime('%Y-%m-%dT%H:%M:%SZ'),
            }
            print(f"[DEBUG] Sending payload: {json.dumps(payload)}")

            try:
                response = await sync_to_async(requests.post)(self.api_url, headers=headers, data=json.dumps(payload))
                response.raise_for_status()
            except requests.exceptions.RequestException as e:
                error_message = f"[ERROR] Request error between {current_start_date} and {current_end_date}: {e}"
                print(error_message)
                report["errors"].append(error_message)
                current_start_date = current_end_date
                continue

            try:
                data = response.json()
                print(f"[DEBUG] Received response: {data}")
            except json.JSONDecodeError as e:
                error_message = f"[ERROR] Ошибка декодирования JSON между {current_start_date} и {current_end_date}: {e}"
                print(error_message)
                report["errors"].append(error_message)
                current_start_date = current_end_date
                continue

            total_count = data.get("count", 0)
            items = data.get("items", [])
            print(f"[DEBUG] Retrieved {len(items)} items (Total: {total_count}).")

            # Если данных нет, пропускаем текущий интервал
            if not items:
                print(f"[WARNING] No items found between {current_start_date} and {current_end_date}.")
            else:
                for idx, item in enumerate(items, start=1):
                    print(f"[DEBUG] Processing item #{idx}/{len(items)}: {item}")
                    try:
                        await self._save_to_db(item)
                        report["processed_items"] += 1
                    except Exception as e:
                        error_message = f"[ERROR] Error processing item {item.get('id', 'Unknown')}: {e}"
                        print(error_message)
                        report["errors"].append(error_message)

            # Отмечаем обработанный интервал
            report["processed_intervals"] += 1

            # Обновляем начало интервала
            current_start_date = current_end_date

        print(f"[DEBUG] Data fetching completed from {start_date} to {end_date}.")
        return report

        
    async def _save_to_db(self, item):
        """
        Сохраняет данные о бронировании в БД.
        Проверяет, существует ли уже бронирование с таким ID.
        """
        try:
            print(f"[DEBUG] Starting to save reservation {item['id']} to the database.")
            
            hotel = await sync_to_async(Hotel.objects.get)(pms=self.pms_config)
            print(f"[DEBUG] Hotel found: {hotel.name}")

            date_format = '%Y-%m-%dT%H:%M:%S'
            print(f"[DEBUG] Parsing check-in and check-out dates for reservation {item['id']}")

            try:
                check_in = datetime.strptime(item["from"], date_format).replace(tzinfo=timezone.utc)
                check_out = datetime.strptime(item["until"], date_format).replace(tzinfo=timezone.utc)
                print(f"[DEBUG] Parsed check-in: {check_in}, check-out: {check_out}")
            except Exception as e:
                print(f"[ERROR] Ошибка парсинга дат для бронирования {item['id']}: {e}")
                raise

            room_number = item.get("roomNumber", "") or "Unknown"
            print(f"[DEBUG] Room number determined: {room_number}")

            print(f"[DEBUG] Checking if reservation with ID {item['id']} already exists.")
            existing_reservation = await sync_to_async(
                Reservation.objects.filter(reservation_id=item["id"]).first
            )()

            if existing_reservation:
                print(f"[DEBUG] Reservation with ID {item['id']} already exists. Updating it...")
                print(f"[DEBUG] Updating existing reservation {item['id']}.")
                await sync_to_async(Reservation.objects.update_or_create)(
                    reservation_id=item["id"],
                    hotel=hotel,
                    defaults={
                        "room_number": room_number,
                        "room_type": item.get("roomTypeName", ""),
                        "check_in": check_in,
                        "check_out": check_out,
                        "status": item.get("checkInStatus", ""),
                        "price": item.get("reservationPrice", 0),
                        "discount": item.get("discount", 0),
                    },
                )
                print(f"[DEBUG] Updated existing reservation {item['id']}.")
            else:
                print(f"[DEBUG] No existing reservation found for ID {item['id']}. Creating a new one...")
                print(f"[DEBUG] Creating a new reservation {item['id']}.")
                await sync_to_async(Reservation.objects.create)(
                    reservation_id=item["id"],
                    hotel=hotel,
                    room_number=room_number,
                    room_type=item.get("roomTypeName", ""),
                    check_in=check_in,
                    check_out=check_out,
                    status=item.get("checkInStatus", ""),
                    price=item.get("reservationPrice", 0),
                    discount=item.get("discount", 0),
                )
                print(f"[DEBUG] Created a new reservation {item['id']}.")

            print(f"[DEBUG] {'Created' if not existing_reservation else 'Updated'} reservation {item['id']} / {hotel.name}.")

        except ValueError as ve:
            print(f"[ERROR] Ошибка обработки даты для бронирования {item['id']}: {ve}")
        except Exception as e:
            print(f"[ERROR] Ошибка сохранения бронирования {item['id']}: {e}")
