TOOL_NAME = "summarize_personal_items"
TOOL_DESCRIPTION = (
    "Summarize email messages or calendar events into a concise overview with key highlights. "
    "Use this after reading inbox/search/calendar results."
)
TOOL_ARGS = '{"source_type": {"type": "string", "enum": ["auto", "email", "calendar"], "default": "auto"}, "items": {"type": "array", "description": "List of email or calendar records"}, "items_json": {"type": "string", "description": "JSON string with list of records (alternative to items)"}, "max_items": {"type": "integer", "default": 5}, "style": {"type": "string", "enum": ["brief", "detailed"], "default": "brief"}}'

import json
import re
from collections import Counter
from datetime import datetime

from tools._std import tool_ok, tool_error

_STOPWORDS = {
    "the", "and", "for", "with", "this", "that", "from", "your", "about", "have", "you",
    "de", "het", "een", "van", "voor", "met", "over", "aan", "bij", "op", "in", "en",
}


def run(args: dict) -> str:
    source_type = str(args.get("source_type") or "auto").strip().lower()
    max_items = _safe_int(args.get("max_items"), default=5, minimum=1, maximum=20)
    style = str(args.get("style") or "brief").strip().lower()

    items = _load_items(args)
    if not isinstance(items, list):
        return tool_error("'items' must be a list or valid JSON list")
    if not items:
        return tool_error("No items provided to summarize")

    kind = source_type if source_type in {"email", "calendar"} else _detect_kind(items)
    if kind == "email":
        data, message = _summarize_emails(items, max_items=max_items, detailed=(style == "detailed"))
    else:
        data, message = _summarize_calendar(items, max_items=max_items, detailed=(style == "detailed"))

    return tool_ok(data, message)


def _load_items(args: dict):
    if isinstance(args.get("items"), list):
        return args.get("items")
    if isinstance(args.get("items_json"), str) and args.get("items_json").strip():
        try:
            loaded = json.loads(args.get("items_json"))
            return loaded
        except Exception:
            return None
    return args.get("items")


def _detect_kind(items: list[dict]) -> str:
    score_email = 0
    score_calendar = 0
    for item in items[:15]:
        if not isinstance(item, dict):
            continue
        keys = {str(k).lower() for k in item.keys()}
        if {"subject", "sender", "from", "preview", "snippet", "message_id"} & keys:
            score_email += 1
        if {"summary", "title", "start", "end", "location", "event_id"} & keys:
            score_calendar += 1
    return "email" if score_email >= score_calendar else "calendar"


def _summarize_emails(items: list[dict], *, max_items: int, detailed: bool) -> tuple[dict, str]:
    clean_items = [i for i in items if isinstance(i, dict)]
    total = len(clean_items)
    unread = sum(1 for i in clean_items if bool(i.get("unread") or i.get("is_unread")))

    senders = Counter()
    subjects = []
    for item in clean_items:
        sender = str(item.get("sender") or item.get("from") or "unknown").strip()
        senders[sender] += 1
        subject = str(item.get("subject") or "").strip()
        if subject:
            subjects.append(subject)

    keywords = _top_keywords(subjects)
    top_senders = [{"sender": s, "count": c} for s, c in senders.most_common(3)]

    highlights = []
    for item in clean_items[:max_items]:
        subject = str(item.get("subject") or "(no subject)").strip()
        sender = str(item.get("sender") or item.get("from") or "unknown").strip()
        when = str(item.get("received") or item.get("date") or "").strip()
        preview = str(item.get("preview") or item.get("snippet") or "").strip()
        line = f"- {subject} (from: {sender}{', ' + when if when else ''})"
        if detailed and preview:
            line += f"\n  {preview[:140]}"
        highlights.append(line)

    message_lines = [
        f"Summary: {total} email item(s).",
        f"Unread: {unread}." if unread else "Unread: 0.",
    ]
    if top_senders:
        sender_line = ", ".join(f"{s['sender']} ({s['count']})" for s in top_senders)
        message_lines.append(f"Top senders: {sender_line}.")
    if keywords:
        message_lines.append(f"Topics: {', '.join(keywords)}.")
    if highlights:
        message_lines.append("Highlights:")
        message_lines.extend(highlights)

    data = {
        "kind": "email",
        "total": total,
        "unread": unread,
        "top_senders": top_senders,
        "keywords": keywords,
        "highlights": highlights,
    }
    return data, "\n".join(message_lines)


def _summarize_calendar(items: list[dict], *, max_items: int, detailed: bool) -> tuple[dict, str]:
    clean_items = [i for i in items if isinstance(i, dict)]
    total = len(clean_items)

    locations = Counter()
    starts = []
    highlights = []

    for item in clean_items:
        location = str(item.get("location") or "").strip()
        if location:
            locations[location] += 1
        start = str(item.get("start") or item.get("start_time") or "").strip()
        if start:
            starts.append(start)

    for item in clean_items[:max_items]:
        title = str(item.get("summary") or item.get("title") or "(untitled event)").strip()
        start = str(item.get("start") or item.get("start_time") or "").strip()
        end = str(item.get("end") or item.get("end_time") or "").strip()
        location = str(item.get("location") or "").strip()
        time_part = start if not end else f"{start} -> {end}"
        extra = f", {location}" if location else ""
        line = f"- {title} ({time_part}{extra})" if time_part else f"- {title}{extra}"
        if detailed:
            desc = str(item.get("description") or "").strip()
            if desc:
                line += f"\n  {desc[:140]}"
        highlights.append(line)

    start_min, start_max = _date_window(starts)
    top_locations = [{"location": loc, "count": cnt} for loc, cnt in locations.most_common(3)]

    message_lines = [f"Summary: {total} calendar event(s)."]
    if start_min and start_max:
        message_lines.append(f"Range: {start_min} to {start_max}.")
    if top_locations:
        loc_line = ", ".join(f"{l['location']} ({l['count']})" for l in top_locations)
        message_lines.append(f"Top locations: {loc_line}.")
    if highlights:
        message_lines.append("Highlights:")
        message_lines.extend(highlights)

    data = {
        "kind": "calendar",
        "total": total,
        "date_range": {"since": start_min, "until": start_max},
        "top_locations": top_locations,
        "highlights": highlights,
    }
    return data, "\n".join(message_lines)


def _safe_int(value, *, default: int, minimum: int, maximum: int) -> int:
    try:
        parsed = int(value)
    except Exception:
        return default
    return max(minimum, min(maximum, parsed))


def _top_keywords(subjects: list[str]) -> list[str]:
    tokens = []
    for subject in subjects:
        for token in re.findall(r"[A-Za-z0-9][A-Za-z0-9_-]{2,}", subject.lower()):
            if token in _STOPWORDS:
                continue
            if token.isdigit():
                continue
            tokens.append(token)
    return [word for word, _ in Counter(tokens).most_common(5)]


def _date_window(starts: list[str]) -> tuple[str, str]:
    parsed_dates = []
    for value in starts:
        date_part = str(value).strip()[:10]
        try:
            parsed_dates.append(datetime.fromisoformat(date_part).date())
        except Exception:
            continue
    if not parsed_dates:
        return "", ""
    return min(parsed_dates).isoformat(), max(parsed_dates).isoformat()
