import emails
import requests
import markdown2
import assistants
import phonenumbers
import dateutil.parser

# def create_lead(bob, thread_id, name, phone, email, platform):
# def save_reply(bob, thread_id, agent_id, user_input, agent_reply, response_time, platform, tokens, duration):
# def save_orphan_reply(bob, thread_id, agent_id, user_input, response_time, platform):
# def get_replies(bob, thread_id):
# def get_unprocessed_threads(bob):
# def summarize_thread(bob, thread_id, platform, name):
# def save_summary(bob, thread_id, summary, duration, platform, conversation_rtf, min_response_time, max_response_time, avg_response_time, first_timestamp_str):



# Add lead to Airtable
def create_lead(bob, thread_id, name, phone, address, platform):
    AIRTABLE_API_KEY = bob['Airtable']['API_KEY']
    AIRTABLE_APP = bob['Airtable']['app_ID']
    AIRTABLE_LEADS_TBL = bob['Airtable']['leads_TBL']
    SMTP_TO_EMAIL = bob['Email']['client_email']
    BOB_ID = bob['ID']['bob_id']

    url = f"https://api.airtable.com/v0/{AIRTABLE_APP}/{AIRTABLE_LEADS_TBL}"
    headers = {
        "Authorization": 'Bearer ' + AIRTABLE_API_KEY,
        "Content-Type": "application/json"
    }
    data = {
        "records": [{
            "fields": {
                "name": name,
                "phone": phone,
                "address": address,
                "platform": platform,
                "thread_id": thread_id,
                "sent_to": SMTP_TO_EMAIL,
                "bob_id": BOB_ID,
                "thread_id": thread_id
            }
        }]
    }
    response = requests.post(url, headers=headers, json=data)

    summary, conversation, tokens = summarize_thread(bob, thread_id, platform, name)

    international_phone = phonenumbers.format_number(
        phonenumbers.parse(phone, 'US'), phonenumbers.PhoneNumberFormat.E164)
    international_phone = international_phone.replace('+', '')
    whatsapp = f"https://wa.me/{international_phone}"

    emails.send_lead(bob,
                     summary=summary,
                     name=name,
                     email=email,
                     phone=phone,
                     whatsapp=whatsapp,
                     platform=platform,
                     transcript=markdown2.markdown(conversation))

    if response.status_code == 200:
        return response.json()
    else:
        print(f"ERROR: Failed to create lead: {response.text}")


# save the user input and the agent's reply to Airtable
def save_reply(bob, thread_id, agent_id, user_input, agent_reply,
               response_time, platform, tokens):
    
    AIRTABLE_API_KEY = bob['Airtable']['API_KEY']
    AIRTABLE_APP = bob['Airtable']['app_ID']
    AIRTABLE_REPLIES_TBL = bob['Airtable']['replies_TBL']

    url = f"https://api.airtable.com/v0/{AIRTABLE_APP}/{AIRTABLE_REPLIES_TBL}"
    headers = {
        "Authorization": 'Bearer ' + AIRTABLE_API_KEY,
        "Content-Type": "application/json"
    }
    data = {
        "records": [{
            "fields": {
                "thread_id": thread_id,
                "bob_id": agent_id,
                "user_input": user_input,
                "agent_reply": agent_reply,
                "response_time": response_time,
                "platform": platform,
                "api_tokens": tokens,
            }
        }]
    }
    response = requests.post(url, headers=headers, json=data)
    if response.status_code == 200:
        ensure_existence(bob, thread_id)
        return response.json()
    else:
        print(f"ERROR: Failed to save reply: {response.text}")


# save the user input and the agent's reply to Airtable
def save_orphan_reply(bob, thread_id, agent_id, user_input, response_time,
                      platform):
    AIRTABLE_API_KEY = bob['Airtable']['API_KEY']
    AIRTABLE_APP = bob['Airtable']['app_ID']
    AIRTABLE_ORPHANS_TBL = bob['Airtable']['orphans_TBL']

    url = f"https://api.airtable.com/v0/{AIRTABLE_APP}/{AIRTABLE_ORPHANS_TBL}"
    print("Saving reply:", url)
    headers = {
        "Authorization": 'Bearer ' + AIRTABLE_API_KEY,
        "Content-Type": "application/json"
    }
    data = {
        "records": [{
            "fields": {
                "thread_id": thread_id,
                "bob_id": agent_id,
                "user_input": user_input,
                "response_time": response_time,
                "platform": platform
            }
        }]
    }
    response = requests.post(url, headers=headers, json=data)
    if response.status_code == 200:
        print("Reply saved successfully.")
        return response.json()
    else:
        print(f"ERROR: Failed to save reply: {response.text}")


#get all the records in the Replies table that match this thread_id, with the most recent first
#maybe this should check if the thread belongs to the same bob
def get_replies(bob, thread_id):
    AIRTABLE_API_KEY = bob['Airtable']['API_KEY']
    AIRTABLE_APP = bob['Airtable']['app_ID']
    AIRTABLE_REPLIES_TBL = bob['Airtable']['replies_TBL']

    url = f"https://api.airtable.com/v0/{AIRTABLE_APP}/{AIRTABLE_REPLIES_TBL}"
    headers = {
        "Authorization": 'Bearer ' + AIRTABLE_API_KEY,
        "Content-Type": "application/json"
    }
    params = {
        "filterByFormula": f"{{thread_id}} = '{thread_id}'",
        "sort[0][field]": "timestamp",
        "sort[0][direction]": "asc"
    }

    offset = None
    all_records = []

    # Initialize an infinite loop to continuously retrieve records using pagination
    while True:
        # If there is an offset, include it in the query parameters
        if offset:
            params["offset"] = offset

        # Send a GET request to the Airtable API with the specified URL, headers, and parameters
        response = requests.get(url, headers=headers, params=params)

        # Check if the response is successful
        if response.status_code == 200:
            # Parse the JSON response and extend the all_records list with "records" key's value
            data = response.json()
            all_records.extend(data.get("records", []))

            # Retrieve the offset value from the response to use in the next iteration
            offset = data.get("offset")

            # If there is no offset in the response, it implies all records have been retrieved, so break the loop
            if not offset:
                break
        else:
            # If the response status code is not 200, log an error message with status code and response text
            print(
                f"ERROR: Failed to retrieve records: {response.status_code} - {response.text}"
            )
            break

    # Return the complete list of records retrieved
    return (all_records)

#get all the records in the Replies table that match this thread_id, with the most recent first
#maybe this should check if the thread belongs to the same bob
def get_user_and_platform(bob, thread_id):
    AIRTABLE_API_KEY = bob['Airtable']['API_KEY']
    AIRTABLE_APP = bob['Airtable']['app_ID']
    AIRTABLE_LEADS_TBL = bob['Airtable']['leads_TBL']
    AIRTABLE_REPLIES_TBL = bob['Airtable']['replies_TBL']

    url = f"https://api.airtable.com/v0/{AIRTABLE_APP}/{AIRTABLE_LEADS_TBL}"
    headers = {
        "Authorization": 'Bearer ' + AIRTABLE_API_KEY,
        "Content-Type": "application/json"
    }
    params = {
        "filterByFormula": f"{{thread_id}} = '{thread_id}'",
        "maxRecords": 1
    }


    # Send a GET request to the Airtable API with the specified URL, headers, and parameters
    response = requests.get(url, headers=headers, params=params)

    if response.status_code == 200:
        # Parse the JSON response and extend the all_records list with "records" key's value
        data = response.json()
        records = data.get("records", [])
        if records:
            record = records[0]
            user = record.get("fields", {}).get("name")
            platform = record.get("fields", {}).get("platform")
            print(f"INFO: Found a lead with User: {user}, Platform: {platform}")
            return user, platform
    else:
        # If the response status code is not 200, log an error message with status code and response text
        print(
            f"ERROR: Failed to retrieve records: {response.status_code} - {response.text}"
        )

    #if the conversation didn't have a lead captured, then find the most recent reply and get the platform value
    name = 'User'
    platform = 'unknown'

    url = f"https://api.airtable.com/v0/{AIRTABLE_APP}/{AIRTABLE_REPLIES_TBL}"
    headers = {
        "Authorization": 'Bearer ' + AIRTABLE_API_KEY,
        "Content-Type": "application/json"
    }
    params = {
        "filterByFormula": f"{{thread_id}} = '{thread_id}'",
        "sort[0][field]": "timestamp",
        "sort[0][direction]": "asc",
        "maxRecords": 1
    }

    response = requests.get(url, headers=headers, params=params)

    if response.status_code == 200:
        # Parse the JSON response and extend the all_records list with "records" key's value
        data = response.json()
        records = data.get("records", [])
        if records:
            record = records[0]
            platform = record.get("fields", {}).get("platform", "unknown")
            print(f"INFO: Found a reply with User: {name}, Platform: {platform}")
            return name, platform

    # If no records found or request failed, return default values
    print("INFO: No records found, using default values")
    return name, platform



#get all the threads in the Threads table that have processed = false, with the most recent first
#consider checking if the thread belongs to the same bob
def get_unprocessed_threads(bob):
    AIRTABLE_API_KEY = bob['Airtable']['API_KEY']
    AIRTABLE_APP = bob['Airtable']['app_ID']
    AIRTABLE_THREADS_TBL = bob['Airtable']['threads_TBL']

    url = f"https://api.airtable.com/v0/{AIRTABLE_APP}/{AIRTABLE_THREADS_TBL}"
    headers = {
        "Authorization": 'Bearer ' + AIRTABLE_API_KEY,
        "Content-Type": "application/json"
    }
    params = {
        "filterByFormula": "{processed} = FALSE()",
        "sort[0][field]": "Created",
        "sort[0][direction]": "asc"
    }

    offset = None
    all_records = []

    while True:
        if offset is not None:
            params["offset"] = offset

        response = requests.get(url, headers=headers, params=params)

        if response.status_code == 200:
            data = response.json()
            all_records.extend(data.get("records", []))

            offset = data.get("offset")

            if not offset:
                break
        else:
            print(
                f"ERROR: Failed to retrieve records: {response.status_code} - {response.text}"
            )
            break

    return all_records


#get all the threads in the Threads table that have processed = false, with the most recent first
#consider checking if the thread belongs to the same bob
def get_thread(bob, thread_id):
    AIRTABLE_API_KEY = bob['Airtable']['API_KEY']
    AIRTABLE_APP = bob['Airtable']['app_ID']
    AIRTABLE_THREADS_TBL = bob['Airtable']['threads_TBL']

    url = f"https://api.airtable.com/v0/{AIRTABLE_APP}/{AIRTABLE_THREADS_TBL}"
    headers = {
        "Authorization": 'Bearer ' + AIRTABLE_API_KEY,
        "Content-Type": "application/json"
    }
    params = {
        "filterByFormula": "{thread_id} = " + thread_id,
        "sort[0][field]": "Created",
        "sort[0][direction]": "asc"
    }

    response = requests.get(url, headers=headers, params=params)

    if response.status_code == 200:
        data = response.json()
        records = data.get('records', [])
        records_count = len(records)

        if records_count == 1:
            return records[0]
        else:
            print(f"ERROR: Expected 1 record for thread_id {thread_id}, but found {records_count}.")
            return None
    else:
        print(
            f"ERROR: Failed to retrieve records: {response.status_code} - {response.text}"
        )

    return None

    while True:
        if offset is not None:
            params["offset"] = offset



        if response.status_code == 200:
            all_records.extend(data.get("records", []))

            offset = data.get("offset")

            if not offset:
                break


    return all_records

#gets the summary of lead information that was captured during this thread
def get_lead_summary(bob, thread_id):
    AIRTABLE_API_KEY = bob['Airtable']['API_KEY']
    AIRTABLE_APP = bob['Airtable']['app_ID']
    AIRTABLE_LEADS_TBL = bob['Airtable']['leads_TBL']

    url = f"https://api.airtable.com/v0/{AIRTABLE_APP}/{AIRTABLE_LEADS_TBL}"
    headers = {
        "Authorization": 'Bearer ' + AIRTABLE_API_KEY,
        "Content-Type": "application/json"
    }
    params = {
        "filterByFormula": f"{{thread_id}} = '{thread_id}'",
        "maxRecords": 1
    }

    response = requests.get(url, headers=headers, params=params)

    if response.status_code == 200:
        # Parse the JSON response and extend the all_records list with "records" key's value
        data = response.json()
        records = data.get("records", [])
        if records:
            record = records[0]
            name = record.get("fields", {}).get("name")
            phone = record.get("fields", {}).get("phone")
            email = record.get("fields", {}).get("email")
            created = record.get("fields", {}).get("Created")
            sent_to = record.get("fields", {}).get("sent_to")
            platform = record.get("fields", {}).get("platform")
            return created + ", " + platform + ", " + sent_to + ", " + name + ", " + email + ", " + phone + "\n"
    else:
        return None

#get all the replies in the thread, send the conversation to a summary agent, save the result to the Threads table
#maybe this function should check if the thread belongs to this bob
def summarize_thread(bob, thread_id, platform, name):
    AGENT_NAME = bob['ID']['name']

    all_records = get_replies(bob, thread_id)

    if len(all_records) == 0:
        return ".","."

    conversation = ''
    conversation_rtf = ''

    first_timestamp_str = all_records[0]['fields']['timestamp']
    first_timestamp = dateutil.parser.isoparse(first_timestamp_str)

    max_response_time = 0
    min_response_time = 100
    total_response_time = 0

    token_total = 0

    # Iterate over the records and concatenate the conversation into the summary  text for HTML email and RTF in Airtable
    for index, record in enumerate(all_records, 1):
        record_line_html = f"\n<strong>" + name + "</strong>: " + record['fields'][
            'user_input'] + "\n\n" + "<strong>" + AGENT_NAME + "</strong>: " + record[
                'fields']['agent_reply'] + "\n<br>"
        record_line_rtf = f"**" + name + "**: " + record['fields'][
            'user_input'] + "" + "**" + AGENT_NAME + "**: " + record['fields'][
                'agent_reply'] + "\n"
        conversation += record_line_html
        conversation_rtf += record_line_rtf
        last_timestamp = dateutil.parser.isoparse(
            record['fields']['timestamp'])
        min_response_time = min(record['fields']['response_time'],
                                min_response_time)
        max_response_time = max(record['fields']['response_time'],
                                max_response_time)
        total_response_time = total_response_time + record['fields'][
            'response_time']

        if 'api_tokens' in record['fields']:
            token_total += record['fields']['api_tokens']

    records_count = len(all_records)
    avg_response_time = total_response_time / records_count

    duration = last_timestamp - first_timestamp
    duration = duration.total_seconds()

    api_token_total = token_total

    summary = assistants.summary(bob, conversation)
    update_thread(bob, thread_id, summary, duration, platform, conversation_rtf,
                 min_response_time, max_response_time, avg_response_time,
                 first_timestamp_str, records_count, api_token_total)

    return summary, conversation, api_token_total


#Saves the summary to Airtable in the Threads table
def update_thread(bob, thread_id, summary, duration, platform, conversation_rtf,
                 min_response_time, max_response_time, avg_response_time,
                 first_timestamp_str, records_count, api_token_total):
    AIRTABLE_API_KEY = bob['Airtable']['API_KEY']
    AIRTABLE_APP = bob['Airtable']['app_ID']
    AIRTABLE_THREADS_TBL = bob['Airtable']['threads_TBL']
    BOB_ID = bob['OpenAI']['bob_id']

    url = f"https://api.airtable.com/v0/{AIRTABLE_APP}/{AIRTABLE_THREADS_TBL}"
    headers = {
        "Authorization": 'Bearer ' + AIRTABLE_API_KEY,
        "Content-Type": "application/json"
    }

    
    params_delete = {
        "filterByFormula": "{thread_id} = '" + thread_id + "'"
    }

    response_delete = requests.get(url, headers=headers, params=params_delete)

    if response_delete.status_code == 200:
        records_to_delete = response_delete.json().get("records", [])
        for record in records_to_delete:
            delete_url = f"https://api.airtable.com/v0/{AIRTABLE_APP}/{AIRTABLE_THREADS_TBL}/{record['id']}"
            response_del = requests.delete(delete_url, headers=headers)
            if response_del.status_code != 200:
                print(f"ERROR: Failed to delete record with ID {record['id']}: {response_del.text}")
    else:
        print(f"ERROR: Failed to retrieve records for deletion: {response_delete.status_code} - {response_delete.text}")
    
    data = {
        "records": [{
            "fields": {
                "thread_id": thread_id,
                "summary": summary,
                "duration": duration,
                "platform": platform,
                "conversation": conversation_rtf,
                "min_response_time": min_response_time,
                "max_response_time": max_response_time,
                "avg_response_time": avg_response_time,
                "Created": first_timestamp_str,
                "bob_id": BOB_ID,
                "replies": records_count,
                "api_tokens": api_token_total,
                "processed": False
            }
        }]
    }

    response = requests.post(url, headers=headers, json=data)

    if response.status_code != 200:
        print(
            f"ERROR: Failed to update Threads table: {response.text}")

    return response.status_code

#Saves the summary to Airtable in the Threads table
def mark_processed(bob, thread_id):
    AIRTABLE_API_KEY = bob['Airtable']['API_KEY']
    AIRTABLE_APP = bob['Airtable']['app_ID']
    AIRTABLE_THREADS_TBL = bob['Airtable']['threads_TBL']

    url = f"https://api.airtable.com/v0/{AIRTABLE_APP}/{AIRTABLE_THREADS_TBL}"
    headers = {
        "Authorization": 'Bearer ' + AIRTABLE_API_KEY,
        "Content-Type": "application/json"
    }
    params = {
        "filterByFormula": f"{{thread_id}} = '{thread_id}'"
    }
    response = requests.get(url, headers=headers, params=params)
    
    if response.status_code == 200:
        records = response.json().get('records', [])
        if records:
            # We found the record, now let's update it
            record = records[0]
            record_id = record['id']

            # Prepare the update data
            update_url = f"{url}/{record_id}"
            update_data = {
                "fields": {
                    "processed": True
                }
            }
            response = requests.patch(update_url, json=update_data, headers=headers)
            if response.status_code != 200:
                print(
                    f"ERROR: Failed to save summary to threads table: {response.text}")

    if response.status_code != 200:
        print(
            f"ERROR: Could not find thread to update: {response.text}")

#makes sure that there's a thread_id line in the Threads table, if not create a blank one so the processing can pick it up
#if there is one, update it to processed = False so it can be picked up by the processing function again, since it has new replies now
def ensure_existence(bob, thread_id):
    AIRTABLE_API_KEY = bob['Airtable']['API_KEY']
    AIRTABLE_APP = bob['Airtable']['app_ID']
    AIRTABLE_THREADS_TBL = bob['Airtable']['threads_TBL']

    url = f"https://api.airtable.com/v0/{AIRTABLE_APP}/{AIRTABLE_THREADS_TBL}"
    headers = {
        "Authorization": 'Bearer ' + AIRTABLE_API_KEY,
        "Content-Type": "application/json"
    }
    params = {
        "filterByFormula": f"{{thread_id}} = '{thread_id}'",
        "maxRecords": 1
    }

    response = requests.get(url, headers=headers, params=params)

    if response.status_code == 200:

        data = response.json()
        records = data.get('records', [])

        if records:
            record_id = records[0]['id']
            update_data = {
                "records": [{
                    "id": record_id,
                    "fields": {
                        "processed": False
                    }
                }]
            }
            response = requests.patch(url, headers=headers, json=update_data)
            if response.status_code != 200:
                print(f"ERROR: Failed to update record: {response.text}")
        else:
            create_data = {
                "records": [{
                    "fields": {
                        "thread_id": thread_id,
                        "processed": False
                    }
                }]
            }
            response = requests.post(url, headers=headers, json=create_data)
            if response.status_code != 200:
                print(f"ERROR: Failed to create record: {response.text}")