# -*- coding: utf-8 -*-

import requests
import logging
import hashlib
import json
from odoo import models, fields, api, _
from datetime import datetime, timedelta
from odoo.exceptions import UserError


_logger = logging.getLogger(__name__)

STATES = ['Active', 'Cancelled']


class ExelyRawBookings(models.Model):
    _name = 'exely.raw.bookings'
    _description = 'Exely Raw Bookings'

    json_data = fields.Json(string="Json Data")
    json_hash_code = fields.Char(string="Hash Code")
    bid = fields.Char(string="Booking Id")

    parent_id = fields.Many2one('exely.raw.bookings', string="Parent Record")
    history_ids = fields.One2many(comodel_name="exely.raw.bookings", inverse_name='parent_id', string="History")
    
    modified_booking_id = fields.Many2one(comodel_name="exely.modified.bookings", string="Modified Bookings Id")


class ExelyRawCompanies(models.Model):
    _name = 'exely.raw.companies'
    _description = 'Exely Raw Companies'

    json_data = fields.Json(string="Json Data")
    json_hash_code = fields.Char(string="Hash Code")
    bid = fields.Char(string="Company Id")

    parent_id = fields.Many2one('exely.raw.companies', string="Parent Record")
    history_ids = fields.One2many(comodel_name="exely.raw.companies", inverse_name='parent_id', string="History")


class ExelyRawRooms(models.Model):
    _name = 'exely.raw.rooms'
    _description = 'Exely Raw Rooms'

    json_data = fields.Json(string="Json Data")
    json_hash_code = fields.Char(string="Hash Code")
    bid = fields.Char(string="Room Id")

    parent_id = fields.Many2one('exely.raw.rooms', string="Parent Record")
    history_ids = fields.One2many(comodel_name="exely.raw.rooms", inverse_name='parent_id', string="History")


class ExelyRawCustomers(models.Model):
    _name = 'exely.raw.customers'
    _description = 'Exely Raw Customers'

    json_data = fields.Json(string="Json Data")
    json_hash_code = fields.Char(string="Hash Code")
    bid = fields.Char(string="Customer Id")

    parent_id = fields.Many2one('exely.raw.customers', string="Parent Record")
    history_ids = fields.One2many(comodel_name="exely.raw.customers", inverse_name='parent_id', string="History")


class ExelyRawRoomstays(models.Model):
    _name = 'exely.raw.roomstays'
    _description = 'Exely Raw Roomstays'

    json_data = fields.Json(string="Json Data")
    json_hash_code = fields.Char(string="Hash Code")
    bid = fields.Char(string="Roomstays Id")

    parent_id = fields.Many2one('exely.raw.roomstays', string="Parent Record")
    history_ids = fields.One2many(comodel_name="exely.raw.roomstays", inverse_name='parent_id', string="History")


class ExelyRawGuests(models.Model):
    _name = 'exely.raw.guests'
    _description = 'Exely Raw Guests'

    json_data = fields.Json(string="Json Data")
    json_hash_code = fields.Char(string="Hash Code")
    bid = fields.Char(string="Guest Id")

    parent_id = fields.Many2one('exely.raw.guests', string="Parent Record")
    history_ids = fields.One2many(comodel_name="exely.raw.guests", inverse_name='parent_id', string="History")


class ExelyRawPayments(models.Model):
    _name = 'exely.raw.payments'
    _description = 'Exely Raw Payments'

    json_data = fields.Json(string="Json Data")
    json_hash_code = fields.Char(string="Hash Code")
    bid = fields.Char(string="Guest Id")

    parent_id = fields.Many2one('exely.raw.payments', string="Parent Record")
    history_ids = fields.One2many(comodel_name="exely.raw.payments", inverse_name='parent_id', string="History")


class ExelyModifiedData(models.Model):
    _name = 'exely.modified.bookings'
    _description = 'Exely Modified Bookings'
    _rec_name = 'booking_number'

    mod_period_start = fields.Datetime(string="Start Date")
    mod_period_end = fields.Datetime(string="End Date")
    booking_number = fields.Char(string="Booking Number")
    status = fields.Char(string="Status")

    def generate_date_ranges(self, start_date, end_date, period, format):
        date_ranges = []
        current_date = start_date
        
        while current_date < end_date:
            period_start = current_date.replace(hour=0, minute=0, second=0, microsecond=0)
            period_end = min(current_date + timedelta(days=period), end_date)
            
            if period_end.date() < end_date.date():
                period_end = period_end.replace(hour=23, minute=59)
            else:
                period_end = end_date
            
            date_ranges.append((
                period_start.strftime(format),
                period_end.strftime(format)
            ))
            
            current_date = period_end + timedelta(days=1)
        return date_ranges

    def get_exely_data_api(self, url, headers):
        response = requests.get(url, headers=headers)
        if response.status_code == 200:
            data = response.json()
            return data
        else:
            return False

    def create_or_update_raw_data(self, data, model, bid):
        json_data = json.dumps(data, sort_keys=True)
        hash_object = hashlib.sha256(json_data.encode())
        hash_hex = hash_object.hexdigest()
        
        found_raw_record = self.env[model].search([
            ('bid', '=', bid),
        ])
        
        if found_raw_record:
            if found_raw_record.json_hash_code != hash_hex:
                # found_raw_record.write({
                #     'json_data': json_data,
                #     'json_hash_code': hash_hex
                # })
                new_created_record = self.env[model].create({
                    'json_data': json_data,
                    'json_hash_code': hash_hex,
                    'bid': bid,
                })
                found_raw_record.parent_id = new_created_record.id
        else:
            found_raw_record = self.env[model].create({
                'json_data': json_data,
                'json_hash_code': hash_hex,
                'bid': bid
            })

    def get_exely_payments(self):
        exely_api_conf = self.env['exely.api.conf'].search([], limit=1)
        if exely_api_conf:
            headers = {
                'X-API-KEY': exely_api_conf.api_key,
                'Content-Type': 'application/json',
            }
        else:
            raise UserError(_("Please configure Exely API Key"))

        start_date = datetime(2024, 1, 1)
        end_date = datetime.now()

        date_ranges = self.generate_date_ranges(start_date, end_date, 7, "%Y%m%d%H%M")

        to_create = []
        for start, end in date_ranges:
            print(f"{start} to {end}")

            payments = self.get_exely_data_api(f"https://connect.hopenapi.com/api/exelypms/v1/analytics/payments?startDateTime={start}&endDateTime={end}&includeServices=true", headers)
            if payments:
                self.create_or_update_raw_data(payments, 'exely.raw.payments', f"{start}{end}")

    def process_exely_payments(self):
        found_payment_record = self.env['hms.bookings'].search([], order="write_date desc", limit=1)
        if False:
            max_date = found_payment_record.write_date
        else:
            max_date = datetime.strptime('1970-01-01', "%Y-%m-%d").date()

        to_process_payments = self.env['exely.raw.payments'].search([('write_date', '>', max_date), ('parent_id', '=', False)])
        
        to_create = []
        for payment in to_process_payments:
            data = json.loads(payment.json_data)
            
            payment_data = data.pop('data', None)
            
            if payment_data:
                all_agents = payment_data.pop('agents', None)
                if all_agents:
                    for agent in all_agents:
                        agent['bid'] = agent.pop('id')

                        email = agent.get('email', None)
                        if email:
                            agent['email'] = self.env['hms.email'].search([('email', '=', email)], limit=1).id or self.env['hms.email'].create({'email': email}).id 
                        phone = agent.get('phone', None)
                        if phone:
                            agent['phone'] = self.env['hms.phones'].search([('phone', '=', phone)], limit=1).id or self.env['hms.phones'].create({'phone': phone}).id

                    if all_agents:
                        for agent in all_agents:
                            found_agent = self.env['hms.agents'].search([('bid', '=', agent['bid'])])
                            if not found_agent:
                                self.env['hms.agents'].create(agent)

                all_roomtypes = payment_data.pop('roomTypes', None)
                if all_roomtypes:
                    for roomtype in all_roomtypes:
                        roomtype['bid'] = roomtype.pop('id')
                        found_roomtype = self.env['hms.room.types'].search([('bid', '=', roomtype['bid'])])
                        if not found_roomtype:
                            self.env['hms.room.types'].create(roomtype)
                        else:
                            found_roomtype.write(roomtype)

                all_services = payment_data.pop('services', None)
                if all_services:
                    for service in all_services:
                        service['bid'] = service.pop('id')

                        kind = service.pop('kind', None)
                        if kind:
                            service['kind'] = self.env['hms.service.kinds'].search([('hms_id', '=', kind)]).id

                        vat_kind = service.pop('vatKind', None)
                        if vat_kind:
                            service['vat_kind'] = self.env['hms.service.vat.kinds'].search([('hms_id', '=', vat_kind)]).id

                        service['service_date'] = datetime.strptime(service.pop('date', None), "%Y%m%d").strftime("%Y-%m-%d")

                        found_service = self.env['hms.services'].search([('bid', '=', service['bid'])])
                        if not found_service:
                            self.env['hms.services'].create(service)

    def get_exely_data(self):
        exely_api_conf = self.env['exely.api.conf'].search([], limit=1)
        if exely_api_conf:
            headers = {
                'X-API-KEY': exely_api_conf.api_key,
                'Content-Type': 'application/json',
            }
        else:
            raise UserError(_("Please configure Exely API Key"))

        companies = self.get_exely_data_api("https://connect.hopenapi.com/api/exelypms/v1/companies", headers)
        if companies:
            for company in companies:
                self.create_or_update_raw_data(company, 'exely.raw.companies', company['id'])

        rooms = self.get_exely_data_api("https://connect.hopenapi.com/api/exelypms/v1/rooms", headers)
        if rooms:
            for room in rooms:
                self.create_or_update_raw_data(room, 'exely.raw.rooms', room['id'])


        start_date = datetime(2024, 1, 1)
        end_date = datetime.now()

        date_ranges = self.generate_date_ranges(start_date, end_date, 29, "%Y-%m-%dT%H:%M")

        to_create = []
        for status in STATES:
            for start, end in date_ranges:
                print(f"{start} to {end}")

                data = self.get_exely_data_api(f"https://connect.hopenapi.com/api/exelypms/v1/bookings?modifiedFrom={start}&modifiedTo={end}&state={status}", headers)
                if data:
                    for booking_number in data['bookingNumbers']:
                        start_write = datetime.strptime(start, "%Y-%m-%dT%H:%M") - timedelta(hours=4)
                        end_write = datetime.strptime(end, "%Y-%m-%dT%H:%M") - timedelta(hours=4)
                        modified_booking_id = self.env['exely.modified.bookings'].search([
                            ('mod_period_start', '=', start_write),
                            ('mod_period_end', '=', end_write), 
                            ('booking_number', '=', booking_number),
                            ('status', '=', status)]
                        )
                        if not modified_booking_id:
                            modified_booking_id = self.env['exely.modified.bookings'].create({
                                'mod_period_start': start_write,
                                'mod_period_end': end_write,
                                'booking_number': booking_number,
                                'status': status
                            })
                        
                        booking = self.get_exely_data_api(f"https://connect.hopenapi.com/api/exelypms/v1/bookings/{booking_number}", headers)
                        if booking:
                            self.create_or_update_raw_data(booking, 'exely.raw.bookings', booking['id'])

                            customer = booking['customer']
                            self.create_or_update_raw_data(customer, 'exely.raw.customers', customer['id'])
                            
                            roomstays = booking['roomStays']
                            for roomstay in roomstays:
                                self.create_or_update_raw_data(roomstay, 'exely.raw.roomstays', roomstay['id'])

                                guests = roomstay['guestsIds']
                                for bid in guests:
                                    guest = self.get_exely_data_api(f"https://connect.hopenapi.com/api/exelypms/v1/guests/{bid}", headers)

                                    self.create_or_update_raw_data(guest, 'exely.raw.guests', bid)

    def process_exely_data(self):
        found_booking_record = self.env['hms.bookings'].search([], order="write_date desc", limit=1)
        if found_booking_record:
            max_date = found_booking_record.write_date
        else:
            max_date = datetime.strptime('1970-01-01', "%Y-%m-%d").date()

        to_process_modified_bookings = self.env['exely.raw.bookings'].search([('write_date', '>', max_date), ('parent_id', '=', False)])
        
        to_create = []
        for modified in to_process_modified_bookings:
            data = json.loads(modified.json_data)

            data['bid'] = data.pop('id')

            customer = data.pop('customer', None)
            if customer:
                customer['bid'] = customer.pop('id')
                if customer.get('emails', None):
                    customer['emails'] = [(6, 0, [
                        self.env['hms.email'].search([('email', '=', email)], limit=1).id or 
                        self.env['hms.email'].create({'email': email}).id 
                        for email in customer['emails']
                    ])]
                if customer.get('phones', None):
                    customer['phones'] = [(6, 0, [
                        self.env['hms.phones'].search([('phone', '=', phone)], limit=1).id or 
                        self.env['hms.phones'].create({'phone': phone}).id 
                        for phone in customer['phones']
                    ])]

                found_customer = self.env['hms.customer'].search([('bid', '=', customer['bid'])])
                if found_customer:
                    customer_id = found_customer.id
                else:
                    customer_id = self.env['hms.customer'].create(customer).id
                data['customer'] = customer_id

            roomstays = data.pop('roomStays', None)
            if roomstays:
                roomstays_ids = []
                for roomstay in roomstays:
                    roomstay['bid'] = roomstay.pop('id')

                    status = roomstay.pop('status', None)
                    if status:
                        found_status_id = self.env['hms.status'].search([('name', '=', status)])
                        if found_status_id:
                            status_id = found_status_id.id
                        else:
                            status_id = self.env['hms.status'].create({'name': status}).id
                        roomstay['status'] = status_id

                    bookingstatus = roomstay.pop('bookingStatus', None)
                    if bookingstatus:
                        found_bookingstatus_id = self.env['hms.booking.status'].search([('name', '=', bookingstatus)])
                        if found_bookingstatus_id:
                            bookingstatus_id = found_bookingstatus_id.id
                        else:
                            bookingstatus_id = self.env['hms.booking.status'].create({'name': bookingstatus}).id
                        roomstay['bookingStatus'] = bookingstatus_id

                    roomTypeId = roomstay.get('roomTypeId', None)
                    if roomTypeId:
                        found_roomtype = self.env['hms.room.types'].search([('bid', '=', roomTypeId)])
                        if found_roomtype:
                            roomtype_id = found_roomtype.id
                        else:
                            roomtype_id = self.env['hms.room.types'].create({'bid': roomTypeId}).id
                        roomstay['roomTypeId'] = roomtype_id

                    roomId = roomstay.get('roomId', None)
                    if roomId:
                        found_raw_room = self.env['exely.raw.rooms'].search([('bid', '=', roomId)])
                        if found_raw_room:
                            room_data = json.loads(found_raw_room.json_data)
                            room_data['bid'] = room_data.pop('id')
                            roomTypeId = room_data.get('roomTypeId', None)
                            if roomTypeId:
                                found_roomtype = self.env['hms.room.types'].search([('bid', '=', roomTypeId)])
                                if found_roomtype:
                                    roomtype_id = found_roomtype.id
                                else:
                                    roomtype_id = self.env['hms.room.types'].create({'bid': roomTypeId}).id
                                room_data['roomTypeId'] = roomtype_id
                    
                            found_room = self.env['hms.rooms'].search([('bid', '=', roomId)])
                            if found_room:
                                room_id = found_room.id
                            else:
                                room_id = self.env['hms.rooms'].create(room_data).id

                            roomstay['roomId'] = room_id

                    

                    guests = roomstay.pop('guestsIds', None)

                    if guests:
                        guest_ids = []
                        for guest in guests:
                            guest_data = json.loads(self.env['exely.raw.guests'].search([('bid', '=', guest)]).json_data)
                            guest_data['bid'] = guest_data.pop('id')
                            
                            if guest_data:
                                if guest_data.get('emails', None):
                                    guest_data['emails'] = [(6, 0, [
                                        self.env['hms.email'].search([('email', '=', email)], limit=1).id or 
                                        self.env['hms.email'].create({'email': email}).id 
                                        for email in guest_data['emails']
                                    ])]
                                if guest_data.get('phones', None):
                                    guest_data['phones'] = [(6, 0, [
                                        self.env['hms.phones'].search([('phone', '=', phone)], limit=1).id or 
                                        self.env['hms.phones'].create({'phone': phone}).id 
                                        for phone in guest_data['phones']
                                    ])]

                                found_guest = self.env['hms.guests'].search([('bid', '=', guest)])
                                if found_guest:
                                    guest_id = found_guest.id
                                else:
                                    guest_id = self.env['hms.guests'].create(guest_data).id
                                guest_ids.append(guest_id)

                        if guest_ids:
                            roomstay['guestsIds'] = [(6, 0, guest_ids)]

                    amenities = roomstay.pop('amenities', None)

                    if not amenities:
                        amenity_ids = []
                        for amenity in amenities:
                            found_amenity = self.env['hms.amenities'].search([('name', '=', amenity)])
                            if found_amenity:
                                amenity_id = found_amenity.id
                            else:
                                amenity_id = self.env['hms.amenities'].create({'name': amenity}).id
                            amenity_ids.append(amenity_id)

                        if amenity_ids:
                            roomstay['amenities'] = [(6, 0, amenity_ids)]

                    found_roomstay = self.env['hms.roomstays'].search([('bid', '=', roomstay['bid'])])
                    if found_roomstay:
                        roomstay_id = found_roomstay.id
                    else:
                        roomstay_id = self.env['hms.roomstays'].create(roomstay).id
                    roomstays_ids.append(roomstay_id)
                
                if roomstays_ids:
                    data['roomStays'] = [(6, 0, roomstays_ids)]

            sourceChannelName = data.pop('sourceChannelName', None)
            if sourceChannelName:
                found_source_channel = self.env['hms.source.channel'].search([('name', '=', sourceChannelName)])
                if found_source_channel:
                    source_channel_id = found_source_channel.id
                else:
                    source_channel_id = self.env['hms.source.channel'].create({'name': sourceChannelName}).id
                data['sourceChannelName'] = source_channel_id

            to_create.append(data)

        if to_create:
            for i in to_create:
                try:
                    self.env['hms.bookings'].create(i)
                except Exception as e:
                    _logger.warning(f"##############################: {i}")


    # DIRECTLY FROM EXELY
    # def process_exely_data(self):
    #     self.sync_room_numbers()

    #     start_date = datetime(2024, 1, 1)
    #     end_date = datetime.now()

    #     date_ranges = self.generate_date_ranges(start_date, end_date)

    #     to_create = []
    #     for status in STATES:
    #         for start, end in date_ranges:
    #             print(f"{start} to {end}")

    #             data = self.get_modified_bookings(start, end, status)
    #             if data:
    #                 for booking_number in data['bookingNumbers']:
    #                     start_write = datetime.strptime(start, "%Y-%m-%dT%H:%M") - timedelta(hours=4)
    #                     end_write = datetime.strptime(end, "%Y-%m-%dT%H:%M") - timedelta(hours=4)
    #                     found_modified_booking = self.env['exely.modified.bookings'].search([
    #                         ('mod_period_start', '=', start_write), 
    #                         ('mod_period_end', '=', end_write), 
    #                         ('booking_number', '=', booking_number),
    #                         ('status', '=', status)]
    #                     )
    #                     if not found_modified_booking:
    #                         self.env['exely.modified.bookings'].create({
    #                             'mod_period_start': start_write,
    #                             'mod_period_end': end_write,
    #                             'booking_number': booking_number,
    #                             'status': status
    #                         })
                        
    #                     data = self.get_booking_info(booking_number)
    #                     if data:
    #                         data['bid'] = data.pop('id')
    #                         customer = data.pop('customer', None)

    #                         if customer:
    #                             customer['bid'] = customer.pop('id')
                                
    #                             if customer.get('emails', None):
    #                                 customer['emails'] = [(6, 0, [
    #                                     self.env['exely.email'].search([('email', '=', email)], limit=1).id or 
    #                                     self.env['exely.email'].create({'email': email}).id 
    #                                     for email in customer['emails']
    #                                 ])]
                                
    #                             if customer.get('phones', None):
    #                                 customer['phones'] = [(6, 0, [
    #                                     self.env['exely.phones'].search([('phone', '=', phone)], limit=1).id or 
    #                                     self.env['exely.phones'].create({'phone': phone}).id 
    #                                     for phone in customer['phones']
    #                                 ])]

    #                             found_customer = self.env['exely.customer'].search([('bid', '=', customer['bid'])])
    #                             if found_customer:
    #                                 customer_id = found_customer.id
    #                             else:
    #                                 customer_id = self.env['exely.customer'].create(customer).id
    #                             data['customer'] = customer_id

    #                         roomstays = data.pop('roomStays', None)
    #                         if roomstays:
    #                             roomstays_ids = []
    #                             for roomstay in roomstays:
    #                                 roomstay['bid'] = roomstay.pop('id')

    #                                 if roomstay.get('roomId', None):
    #                                     roomstay['roomId'] = self.env['exely.rooms'].search([('bid', '=', roomstay['roomId'])]).id
                                    
    #                                 guests = roomstay.pop('guestsIds', None)

    #                                 if guests:
    #                                     guest_ids = []
    #                                     for guest in guests:
    #                                         guest_data = self.get_guest_info(guest)
    #                                         guest_data['bid'] = guest_data.pop('id')
                                            
    #                                         if guest_data:
    #                                             if guest_data.get('emails', None):
    #                                                 guest_data['emails'] = [(6, 0, [
    #                                                     self.env['exely.email'].search([('email', '=', email)], limit=1).id or 
    #                                                     self.env['exely.email'].create({'email': email}).id 
    #                                                     for email in guest_data['emails']
    #                                                 ])]
    #                                             if guest_data.get('phones', None):
    #                                                 guest_data['phones'] = [(6, 0, [
    #                                                     self.env['exely.phones'].search([('phone', '=', phone)], limit=1).id or 
    #                                                     self.env['exely.phones'].create({'phone': phone}).id 
    #                                                     for phone in guest_data['phones']
    #                                                 ])]

    #                                             found_guest = self.env['exely.guests'].search([('bid', '=', guest)])
    #                                             if found_guest:
    #                                                 guest_id = found_guest.id
    #                                             else:
    #                                                 guest_id = self.env['exely.guests'].create(guest_data).id
    #                                             guest_ids.append(guest_id)

    #                                     if guest_ids:
    #                                         roomstay['guestsIds'] = [(6, 0, guest_ids)]

    #                                 amenities = roomstay.pop('amenities', None)

    #                                 if not amenities:
    #                                     amenity_ids = []
    #                                     for amenity in amenities:
    #                                         found_amenity = self.env['exely.amenities'].search([('name', '=', amenity)])
    #                                         if found_amenity:
    #                                             amenity_id = found_amenity.id
    #                                         else:
    #                                             amenity_id = self.env['exely.amenities'].create({'name': amenity}).id
    #                                         amenity_ids.append(amenity_id)

    #                                     if amenity_ids:
    #                                         roomstay['amenities'] = [(6, 0, amenity_ids)]

    #                                 found_roomstay = self.env['exely.roomstays'].search([('bid', '=', roomstay['bid'])])
    #                                 if found_roomstay:
    #                                     roomstay_id = found_roomstay.id
    #                                 else:
    #                                     roomstay_id = self.env['exely.roomstays'].create(roomstay).id
    #                                 roomstays_ids.append(roomstay_id)
                                
    #                             if roomstays_ids:
    #                                 data['roomStays'] = [(6, 0, roomstays_ids)]

    #                         to_create.append(data)
    #             else:
    #                 _logger.warning(f"Failed to retrieve data. Status code: {response.status_code}")
    #             # except Exception as e:
    #             #     _logger.warning(f"Error processing data: {e}")
                
    #             if to_create:
    #                 for i in to_create:
    #                     try:
    #                         self.env['exely.bookings'].create(i)
    #                     except Exception as e:
    #                         _logger.warning(f"##############################: {i}")
    #             break
    #     cr.commit()

        
        # if to_create:
        #     self.env['exely.bookings'].create(to_create)


class HmsBookings(models.Model):
    _inherit = 'hms.bookings'
    _description = 'Hms Bookings'
    _rec_name = 'bid'

    