import requests

LINE_URL = "https://api.line.me/v2/bot"

class LineBot:
    def __init__(self, access_token: str):
        self.access_token = access_token
        self.headers = {
            "Content-Type": "application/json",
            "Authorization": f"Bearer {self.access_token}"
        }

class CraftMessage:
    @staticmethod
    def text(text):
        return {"type": "text", "text": text}

    @staticmethod
    def imagemap(alt_text, image_link, landing_page, width, height):
        return {
            "type": "imagemap",
            "baseUrl": image_link,
            "altText": alt_text,
            "baseSize": {"width": int(width), "height": int(height)},
            "actions": [{
                "type": "uri",
                "linkUri": landing_page,
                "area": {
                    "x": 0, "y": 0, "width": int(width), "height": int(height)
                }
            }]
        }

    @staticmethod
    def quick_reply(text, options):
        return {
            "type": "text",
            "text": text,
            "quickReply": {
                "items": [{
                    "type": "action",
                    "action": {
                        "type": "message",
                        "label": opt,
                        "text": opt
                    }
                } for opt in options]
            }
        }

    @staticmethod
    def push_message(to, messages):
        return {"to": to, "messages": messages}

    @staticmethod
    def narrowcast_message(messages, recipient):
        return {"messages": messages, "recipient": recipient}

    @staticmethod
    def build_recipient(operator=None, audience=[]):
        major = next((a for a in audience if a['type'] == 'major'), None)
        if not major:
            return None

        base = {
            "type": "operator",
            operator: [{"type": "audience", "audienceGroupId": int(major['id'])}]
        }

        minors = [
            {"type": "audience", "audienceGroupId": int(a['id'])}
            if a.get('operator') == 'and' or operator == 'or'
            else {"type": "operator", a['operator']: {"type": "audience", "audienceGroupId": int(a['id'])}}
            for a in audience if a['type'] == 'minor'
        ]
        base[operator].extend(minors)
        return base

class MessageClient(LineBot):
    def push(self, payload):
        return requests.post(f"{LINE_URL}/message/push", headers=self.headers, json=payload)
    
    def broadcast(self, payload):
        return requests.post(f"{LINE_URL}/message/broadcast", headers=self.headers, json=payload)

    def narrowcast(self, payload):
        return requests.post(f"{LINE_URL}/message/narrowcast", headers=self.headers, json=payload)

    def validate_narrowcast(self, payload):
        return requests.post(f"{LINE_URL}/message/validate/narrowcast", headers=self.headers, json=payload)

class AudienceClient(LineBot):
    def create(self, name, audiences):
        body = {
            "description": name,
            "audiences": [{"id": uid} for uid in audiences if uid]
        }
        return requests.post(f"{LINE_URL}/audienceGroup/upload", headers=self.headers, json=body)

    def delete(self, audience_id):
        return requests.delete(f"{LINE_URL}/audienceGroup/{audience_id}", headers=self.headers)

    def append(self, audience_id, user_ids):
        body = {
            "audienceGroupId": int(audience_id),
            "audiences": [{"id": uid} for uid in user_ids if uid]
        }
        return requests.put(f"{LINE_URL}/audienceGroup/upload", headers=self.headers, json=body)

    def get_stats(self, audience_id):
        return requests.get(f"{LINE_URL}/audienceGroup/{audience_id}", headers=self.headers)

    def list_all(self):
        page = 1
        results = []
        while True:
            res = requests.get(f"{LINE_URL}/audienceGroup/list?size=40&page={page}", headers=self.headers)
            data = res.json()
            results.extend(data.get("audienceGroups", []))
            if not data.get("hasNextPage"):
                break
            page += 1
        return results

class OAClient(LineBot):
    def get_profile(self):
        return requests.get(f"{LINE_URL}/info", headers=self.headers)

    def get_quota(self):
        usage = requests.get(f"{LINE_URL}/message/quota/consumption", headers=self.headers).json().get("totalUsage")
        total = requests.get(f"{LINE_URL}/message/quota", headers=self.headers).json().get("value")
        return {"quota": total, "consumption": usage, "remaining": total - usage}

    def get_webhook(self):
        resp = requests.get(f"{LINE_URL}/channel/webhook/endpoint", headers=self.headers)
        return resp.status_code, resp.content

    def set_webhook(self, endpoint):
        data = {"endpoint": endpoint}
        resp = requests.put(f"{LINE_URL}/channel/webhook/endpoint", headers=self.headers, json=data)
        return resp.status_code, resp.content

    def get_user_profile(self, user_id):
        url = f"https://api.line.me/v2/bot/profile/{user_id}"
        res = requests.get(url, headers=self.headers)
        if res.status_code == 200:
            return res.json()
        raise Exception(f"Failed to get profile: {res.status_code} {res.text}")
