import asyncio
import aiohttp
import os
import sys
import json
from typing import Optional, Dict, Any
from dotenv import load_dotenv
import urllib.parse
import re

load_dotenv()

SKETCHERS_UNITED_SESSION = os.environ.get('SKETCHERS_UNITED_SESSION')
REMEMBER_WEB = os.environ.get('REMEMBER_WEB')
TARGET_URL = 'https://sketchersunited.org/chats'
API_PASSWORD = os.environ.get('API_PASSWORD')
XSRF_TOKEN = os.environ.get('XSRF_TOKEN')

def get_session_cookie_header() -> Optional[Dict[str, str]]:
    if not SKETCHERS_UNITED_SESSION or not REMEMBER_WEB:
        print("Missing required session or remember_web environment variables.", file=sys.stderr)
        return None

    cookies_to_send = []
    cookies_to_send.append(f"sketchers_united_session={SKETCHERS_UNITED_SESSION}")
    cookies_to_send.append(f"remember_web_59ba36addc2b2f9401580f014c7f58ea4e30989d={REMEMBER_WEB}")

    if XSRF_TOKEN:
        cookies_to_send.append(f"XSRF-TOKEN={XSRF_TOKEN}")

    cookie_header = "; ".join(cookies_to_send)

    return {
        'Cookie': cookie_header,
        'Accept': 'application/json',
        'User-Agent': 'usernames chat checking bot',
        'Content-Type': 'application/json',
    }

def get_post_headers(xsrf_token: str) -> Dict[str, str]:
    return {
        'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64; rv:133.0) Gecko/20100101 Firefox/133.0',
        'Accept': 'application/json, text/plain, */*',
        'Accept-Language': 'en-US,en;q=0.5',
        'X-XSRF-TOKEN': xsrf_token,
        'Sec-GPC': '1',
        'Sec-Fetch-Dest': 'empty',
        'Sec-Fetch-Mode': 'cors',
        'Sec-Fetch-Site': 'same-origin',
        'Priority': 'u=0',
    }

async def make_new_json_request(user_id: int):
    url = f'https://secretsketchers.sketchersunitedcollab.com/api/token/{user_id}'
    data = {
        'password': API_PASSWORD
    }

    headers = {
        'Content-Type': 'application/json',
        'Accept': 'application/json',
    }

    async with aiohttp.ClientSession() as session:
        async with session.post(url, json=data, headers=headers) as response:
            response_text = await response.text()
            if(len(response_text) < 14):
                return response_text
            else:
                return False

async def post_chat_update(session: aiohttp.ClientSession, chat_object: Dict[str, Any], xsrf_token: str):
    pattern = r'/(\d+)/'
    match = re.search(pattern, chat_object.get('icon_url'))

    token = await make_new_json_request(match.group(1))
    form_data = aiohttp.FormData()
    if(token):
        form_data.add_field('text', f"""You've signed up for the Secret Sketchers event, your link is https://secretsketchers.sketchersunitedcollab.com/profile/{token} - it is private and should only be used by you.
            \nDon't want to be in it anymore? Go to https://secretsketchers.sketchersunitedcollab.com/withdraw/{token} - note that withdrawing is permanent and you cannot re-enter the event.""")
    else:
        form_data.add_field('text', f"""Something went wrong, Sorry I will fix it sooner or later... maybe""")

    headers = get_post_headers(xsrf_token)

    try:
        cookie_headers = get_session_cookie_header()
        if cookie_headers:
            headers['Cookie'] = cookie_headers['Cookie']

        async with session.post(
            f"{TARGET_URL}/{chat_object.get('id')}/messages",
            data=form_data,
            headers=headers
        ) as response:
            if response.status not in [200, 201]:
                text = await response.text()
                print(f" Status: {response.status}. Response: {text}", file=sys.stderr)
    except aiohttp.ClientError as e:
        print(f"-> POST ERROR: Client error during update for chat ID {chat_object.get('id', 'N/A')}: {e}", file=sys.stderr)
    except Exception as e:
        print(f"-> POST ERROR: Unexpected error during update for chat ID {chat_object.get('id', 'N/A')}: {e}", file=sys.stderr)



async def process_chats():
    global XSRF_TOKEN

    async with aiohttp.ClientSession() as session:
        headers = get_session_cookie_header()
        if not headers:
            return

        async with session.get(TARGET_URL, headers=headers) as response:
            if response.status != 200:
                print(f"failed: {response.status}", file=sys.stderr)
                return

            try:
                chat_data_array = await response.json()
                if not isinstance(chat_data_array, list):
                    print("not json", file=sys.stderr)
                    return

            except aiohttp.ContentTypeError:
                print("also not json", file=sys.stderr)
                return

        fresh_xsrf_token = None
        for cookie in session.cookie_jar:
            if cookie.key == "XSRF-TOKEN":
                fresh_xsrf_token = urllib.parse.unquote(cookie.value)
                break

        XSRF_TOKEN = fresh_xsrf_token

        for index, chat_object in enumerate(chat_data_array):
            if(chat_object.get('type') == 'private'):
                seen_at_value = chat_object.get('seen_at')
                is_unread = False

                try:
                    if isinstance(seen_at_value, dict):
                        is_unread = True
    #                     print(f"Chat {index}: Status: DICT (New Chat) -> Unread: True")
                    else:
                        latest_created_at = chat_object.get('latest', {}).get('created_at', 0)
                        seen_at_int = int(seen_at_value) if seen_at_value is not None else 0

                        is_unread = seen_at_int < latest_created_at
    #                     print(f"Chat {index}: Seen at ({seen_at_int}) < Latest message ({latest_created_at}) -> Unread: {is_unread}")

                except (AttributeError, TypeError, ValueError) as e:
                    is_unread = False

                if is_unread:
                    await post_chat_update(session, chat_object, fresh_xsrf_token)


async def main_loop():
    while True:
        try:
            await process_chats()
            await asyncio.sleep(5)

        except asyncio.CancelledError:
            print("cancelled normally (ok knowing my luck the error is gonna be this one every single time even tho it never actually is an error like this!) cute puppy: Hiiii")
            break
        except Exception as e:
            print(f"error {e}")
            await asyncio.sleep(5)

if __name__ == "__main__":
    asyncio.run(main_loop())
