from typing import Optional
import logging

from fastapi import APIRouter, Depends, HTTPException, Query, Request
from pydantic import BaseModel

from app.core.auth_service import AuthService
from app.core.auth_dependencies import get_current_user
from app.core.database import execute_query, execute_query_single, execute_update

from .service import build_bottom_bar_state, get_own_timer_snapshot, get_unassigned_open_cases

router = APIRouter()
logger = logging.getLogger(__name__)
_USER_NOTES_SCHEMA_READY = False


class BossAssignPayload(BaseModel):
    case_id: int
    assignee_user_id: int


class BossAssignNextPayload(BaseModel):
    assignee_user_id: int


class UserNoteCreatePayload(BaseModel):
    title: Optional[str] = None
    content: str
    is_pinned: bool = False


class UserNoteUpdatePayload(BaseModel):
    title: Optional[str] = None
    content: Optional[str] = None
    is_pinned: Optional[bool] = None
    is_archived: Optional[bool] = None


class NoteToCaseCommentPayload(BaseModel):
    sag_id: int
    excerpt: Optional[str] = None


class NoteToContactPayload(BaseModel):
    contact_id: int
    field: str
    value: Optional[str] = None
    excerpt: Optional[str] = None
    mode: str = "append"


class NoteToCustomerPayload(BaseModel):
    customer_id: int
    field: str
    value: Optional[str] = None
    excerpt: Optional[str] = None
    mode: str = "append"


def _ensure_user_notes_schema() -> None:
    global _USER_NOTES_SCHEMA_READY
    if _USER_NOTES_SCHEMA_READY:
        return

    exists = execute_query_single("SELECT to_regclass('public.user_notes') AS table_name") or {}
    if exists.get("table_name"):
        _USER_NOTES_SCHEMA_READY = True
        return

    execute_query(
        """
        CREATE TABLE IF NOT EXISTS user_notes (
            id SERIAL PRIMARY KEY,
            user_id INTEGER NOT NULL REFERENCES users(user_id) ON DELETE CASCADE,
            title VARCHAR(200) NOT NULL DEFAULT '',
            content TEXT NOT NULL,
            is_pinned BOOLEAN NOT NULL DEFAULT FALSE,
            is_archived BOOLEAN NOT NULL DEFAULT FALSE,
            created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
            updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
            deleted_at TIMESTAMP NULL
        )
        """
    )

    execute_query(
        """
        CREATE INDEX IF NOT EXISTS idx_user_notes_user_active
            ON user_notes (user_id, is_archived, is_pinned, updated_at DESC)
            WHERE deleted_at IS NULL
        """
    )
    execute_query(
        """
        CREATE INDEX IF NOT EXISTS idx_user_notes_user_updated
            ON user_notes (user_id, updated_at DESC)
            WHERE deleted_at IS NULL
        """
    )
    execute_query(
        """
        CREATE OR REPLACE FUNCTION update_user_notes_updated_at()
        RETURNS TRIGGER AS $$
        BEGIN
            NEW.updated_at = CURRENT_TIMESTAMP;
            RETURN NEW;
        END;
        $$ LANGUAGE plpgsql
        """
    )
    execute_query("DROP TRIGGER IF EXISTS trg_user_notes_updated_at ON user_notes")
    execute_query(
        """
        CREATE TRIGGER trg_user_notes_updated_at
            BEFORE UPDATE ON user_notes
            FOR EACH ROW
            EXECUTE FUNCTION update_user_notes_updated_at()
        """
    )

    _USER_NOTES_SCHEMA_READY = True
    logger.warning("⚠️ user_notes table was missing and has been created automatically")


def _resolve_current_user_display_name(current_user: dict) -> str:
    current_user_id = current_user.get("id")
    if current_user_id is None:
        return "System"

    row = execute_query_single(
        """
        SELECT full_name, username
        FROM users
        WHERE user_id = %s
        """,
        (int(current_user_id),),
    ) or {}
    return str(row.get("full_name") or row.get("username") or f"Bruger #{current_user_id}")


def _get_owned_note_or_404(note_id: int, user_id: int) -> dict:
    _ensure_user_notes_schema()
    row = execute_query_single(
        """
        SELECT id, user_id, title, content, is_pinned, is_archived, created_at, updated_at
        FROM user_notes
        WHERE id = %s
          AND user_id = %s
          AND deleted_at IS NULL
        """,
        (int(note_id), int(user_id)),
    )
    if not row:
        raise HTTPException(status_code=404, detail="Note ikke fundet")
    return row


def _normalize_note_text(value: Optional[str]) -> str:
    return str(value or "").strip()


def _build_merge_value(current_value: Optional[str], incoming_value: str, mode: str) -> str:
    incoming = _normalize_note_text(incoming_value)
    if not incoming:
        return str(current_value or "")

    current = str(current_value or "").strip()
    normalized_mode = str(mode or "append").strip().lower()
    if normalized_mode == "replace":
        return incoming

    if not current:
        return incoming
    if incoming in current:
        return current
    return f"{current}\n{incoming}"


@router.get("/notes")
@router.get("/notes/")
async def list_user_notes(
    include_archived: bool = Query(default=False),
    limit: int = Query(default=50, ge=1, le=200),
    offset: int = Query(default=0, ge=0),
    current_user: dict = Depends(get_current_user),
):
    current_user_id = current_user.get("id")
    if current_user_id is None:
        raise HTTPException(status_code=401, detail="Not authenticated")
    _ensure_user_notes_schema()

    rows = execute_query(
        """
        SELECT id, title, content, is_pinned, is_archived, created_at, updated_at
        FROM user_notes
        WHERE user_id = %s
          AND deleted_at IS NULL
          AND (%s = TRUE OR is_archived = FALSE)
        ORDER BY is_pinned DESC, updated_at DESC, id DESC
        LIMIT %s OFFSET %s
        """,
        (int(current_user_id), bool(include_archived), int(limit), int(offset)),
    ) or []

    total_row = execute_query_single(
        """
        SELECT COUNT(*) AS count
        FROM user_notes
        WHERE user_id = %s
          AND deleted_at IS NULL
          AND (%s = TRUE OR is_archived = FALSE)
        """,
        (int(current_user_id), bool(include_archived)),
    ) or {}

    return {
        "items": rows,
        "count": int(total_row.get("count") or 0),
    }


@router.post("/notes")
@router.post("/notes/")
async def create_user_note(payload: UserNoteCreatePayload, current_user: dict = Depends(get_current_user)):
    current_user_id = current_user.get("id")
    if current_user_id is None:
        raise HTTPException(status_code=401, detail="Not authenticated")
    _ensure_user_notes_schema()

    content = _normalize_note_text(payload.content)
    if not content:
        raise HTTPException(status_code=400, detail="Note-indhold kan ikke være tomt")

    title = _normalize_note_text(payload.title)
    row = execute_query_single(
        """
        INSERT INTO user_notes (user_id, title, content, is_pinned)
        VALUES (%s, %s, %s, %s)
        RETURNING id, title, content, is_pinned, is_archived, created_at, updated_at
        """,
        (int(current_user_id), title, content, bool(payload.is_pinned)),
    )

    return row or {}


@router.patch("/notes/{note_id}")
@router.patch("/notes/{note_id}/")
async def update_user_note(note_id: int, payload: UserNoteUpdatePayload, current_user: dict = Depends(get_current_user)):
    current_user_id = current_user.get("id")
    if current_user_id is None:
        raise HTTPException(status_code=401, detail="Not authenticated")
    _ensure_user_notes_schema()

    _get_owned_note_or_404(note_id, int(current_user_id))

    sets = []
    params = []

    if payload.title is not None:
        sets.append("title = %s")
        params.append(_normalize_note_text(payload.title))
    if payload.content is not None:
        content = _normalize_note_text(payload.content)
        if not content:
            raise HTTPException(status_code=400, detail="Note-indhold kan ikke være tomt")
        sets.append("content = %s")
        params.append(content)
    if payload.is_pinned is not None:
        sets.append("is_pinned = %s")
        params.append(bool(payload.is_pinned))
    if payload.is_archived is not None:
        sets.append("is_archived = %s")
        params.append(bool(payload.is_archived))

    if not sets:
        return _get_owned_note_or_404(note_id, int(current_user_id))

    params.extend([int(note_id), int(current_user_id)])
    row = execute_query_single(
        f"""
        UPDATE user_notes
        SET {', '.join(sets)}
        WHERE id = %s
          AND user_id = %s
          AND deleted_at IS NULL
        RETURNING id, title, content, is_pinned, is_archived, created_at, updated_at
        """,
        tuple(params),
    )
    if not row:
        raise HTTPException(status_code=404, detail="Note ikke fundet")
    return row


@router.delete("/notes/{note_id}")
@router.delete("/notes/{note_id}/")
async def delete_user_note(note_id: int, current_user: dict = Depends(get_current_user)):
    current_user_id = current_user.get("id")
    if current_user_id is None:
        raise HTTPException(status_code=401, detail="Not authenticated")
    _ensure_user_notes_schema()

    deleted = execute_update(
        """
        UPDATE user_notes
        SET deleted_at = CURRENT_TIMESTAMP
        WHERE id = %s
          AND user_id = %s
          AND deleted_at IS NULL
        """,
        (int(note_id), int(current_user_id)),
    )
    if not deleted:
        raise HTTPException(status_code=404, detail="Note ikke fundet")
    return {"status": "deleted", "note_id": int(note_id)}


@router.post("/notes/{note_id}/actions/sag-comment")
@router.post("/notes/{note_id}/actions/sag-comment/")
async def note_to_case_comment(note_id: int, payload: NoteToCaseCommentPayload, current_user: dict = Depends(get_current_user)):
    current_user_id = current_user.get("id")
    if current_user_id is None:
        raise HTTPException(status_code=401, detail="Not authenticated")

    note = _get_owned_note_or_404(note_id, int(current_user_id))
    case_row = execute_query_single(
        """
        SELECT id
        FROM sag_sager
        WHERE id = %s
          AND deleted_at IS NULL
        """,
        (int(payload.sag_id),),
    )
    if not case_row:
        raise HTTPException(status_code=404, detail="Sag ikke fundet")

    text = _normalize_note_text(payload.excerpt) or _normalize_note_text(note.get("content"))
    if not text:
        raise HTTPException(status_code=400, detail="Ingen tekst at indsætte")

    author = _resolve_current_user_display_name(current_user)
    created = execute_query_single(
        """
        INSERT INTO sag_kommentarer (sag_id, indhold, forfatter)
        VALUES (%s, %s, %s)
        RETURNING id, sag_id, indhold, forfatter, created_at
        """,
        (int(payload.sag_id), text, author),
    ) or {}

    return {
        "status": "inserted",
        "target": "sag_comment",
        "note_id": int(note_id),
        "sag_id": int(payload.sag_id),
        "comment": created,
    }


@router.post("/notes/{note_id}/actions/contact-update")
@router.post("/notes/{note_id}/actions/contact-update/")
async def note_to_contact_update(note_id: int, payload: NoteToContactPayload, current_user: dict = Depends(get_current_user)):
    current_user_id = current_user.get("id")
    if current_user_id is None:
        raise HTTPException(status_code=401, detail="Not authenticated")

    note = _get_owned_note_or_404(note_id, int(current_user_id))
    allowed_fields = {"phone", "mobile", "email", "title", "department"}
    field = str(payload.field or "").strip().lower()
    if field not in allowed_fields:
        raise HTTPException(status_code=400, detail="Ugyldigt kontaktfelt")

    contact = execute_query_single(
        f"SELECT id, {field} FROM contacts WHERE id = %s",
        (int(payload.contact_id),),
    )
    if not contact:
        raise HTTPException(status_code=404, detail="Kontakt ikke fundet")

    incoming = _normalize_note_text(payload.value) or _normalize_note_text(payload.excerpt) or _normalize_note_text(note.get("content"))
    if not incoming:
        raise HTTPException(status_code=400, detail="Ingen tekst at indsætte")

    merged = _build_merge_value(contact.get(field), incoming, payload.mode)
    updated = execute_query_single(
        f"""
        UPDATE contacts
        SET {field} = %s,
            updated_at = CURRENT_TIMESTAMP
        WHERE id = %s
        RETURNING id, {field}
        """,
        (merged, int(payload.contact_id)),
    ) or {}

    return {
        "status": "updated",
        "target": "contact",
        "note_id": int(note_id),
        "contact_id": int(payload.contact_id),
        "field": field,
        "value": updated.get(field),
    }


@router.post("/notes/{note_id}/actions/customer-update")
@router.post("/notes/{note_id}/actions/customer-update/")
async def note_to_customer_update(note_id: int, payload: NoteToCustomerPayload, current_user: dict = Depends(get_current_user)):
    current_user_id = current_user.get("id")
    if current_user_id is None:
        raise HTTPException(status_code=401, detail="Not authenticated")

    note = _get_owned_note_or_404(note_id, int(current_user_id))
    field = str(payload.field or "").strip().lower()
    allowed_fields = {"phone", "mobile_phone", "email", "address", "invoice_email", "note"}
    if field not in allowed_fields:
        raise HTTPException(status_code=400, detail="Ugyldigt firmafelt")

    customer = execute_query_single(
        "SELECT id FROM customers WHERE id = %s",
        (int(payload.customer_id),),
    )
    if not customer:
        raise HTTPException(status_code=404, detail="Firma ikke fundet")

    incoming = _normalize_note_text(payload.value) or _normalize_note_text(payload.excerpt) or _normalize_note_text(note.get("content"))
    if not incoming:
        raise HTTPException(status_code=400, detail="Ingen tekst at indsætte")

    if field == "note":
        author = _resolve_current_user_display_name(current_user)
        created = execute_query_single(
            """
            INSERT INTO customer_notes (customer_id, note_type, note, created_by)
            VALUES (%s, %s, %s, %s)
            RETURNING id, customer_id, note_type, note, created_by, created_at
            """,
            (int(payload.customer_id), "general", incoming, author),
        ) or {}
        return {
            "status": "inserted",
            "target": "customer_note",
            "note_id": int(note_id),
            "customer_id": int(payload.customer_id),
            "record": created,
        }

    current = execute_query_single(
        f"SELECT {field} FROM customers WHERE id = %s",
        (int(payload.customer_id),),
    ) or {}
    merged = _build_merge_value(current.get(field), incoming, payload.mode)
    updated = execute_query_single(
        f"""
        UPDATE customers
        SET {field} = %s,
            updated_at = CURRENT_TIMESTAMP
        WHERE id = %s
        RETURNING id, {field}
        """,
        (merged, int(payload.customer_id)),
    ) or {}

    return {
        "status": "updated",
        "target": "customer",
        "note_id": int(note_id),
        "customer_id": int(payload.customer_id),
        "field": field,
        "value": updated.get(field),
    }


def _resolve_user_id_from_request(request: Request) -> Optional[int]:
    state_user_id = getattr(request.state, "user_id", None)
    if state_user_id is not None:
        try:
            return int(state_user_id)
        except (TypeError, ValueError):
            pass

    user_id_param = request.query_params.get("user_id")
    if user_id_param:
        try:
            return int(user_id_param)
        except (TypeError, ValueError):
            pass

    token = (request.cookies.get("access_token") or "").strip() or None
    payload = AuthService.verify_token(token) if token else None
    sub_claim = payload.get("sub") if payload else None
    if sub_claim is not None:
        try:
            return int(sub_claim)
        except (TypeError, ValueError):
            return None
    return None

@router.get("/state")
async def get_bottom_bar_state(request: Request, current_user: dict = Depends(get_current_user)):
    current_user_id = current_user.get("id")
    if current_user_id is None:
        raise HTTPException(status_code=401, detail="Not authenticated")
    user_id = int(current_user_id)
    force_boss_access = bool(current_user.get("is_superadmin") or current_user.get("is_shadow_admin"))
    context_path = request.query_params.get("context") or ""
    return build_bottom_bar_state(user_id, context_path=context_path, force_boss_access=force_boss_access)


@router.get("/timers/own")
async def get_own_timers(
    paused_limit: int = Query(default=10, ge=1, le=25),
    current_user: dict = Depends(get_current_user),
):
    current_user_id = current_user.get("id")
    if current_user_id is None:
        raise HTTPException(status_code=401, detail="Not authenticated")
    return get_own_timer_snapshot(int(current_user_id), paused_limit=paused_limit)


@router.get("/boss/unassigned-cases")
async def list_unassigned_open_cases(
    limit: int = Query(default=25, ge=1, le=100),
    current_user: dict = Depends(get_current_user),
):
    if not _has_boss_access(current_user):
        raise HTTPException(status_code=403, detail="Insufficient permissions for boss action")
    return get_unassigned_open_cases(limit=limit)

from app.services.task_routing import TaskRouter
from app.services.m365_calendar import M365CalendarService


def _has_boss_access(current_user: dict) -> bool:
    if bool(current_user.get("is_superadmin") or current_user.get("is_shadow_admin")):
        return True

    current_user_id = current_user.get("id")
    if current_user_id is None:
        return False

    rows = execute_query(
        """
        SELECT LOWER(g.name) AS name
        FROM user_groups ug
        JOIN groups g ON g.id = ug.group_id
        WHERE ug.user_id = %s
        """,
        (int(current_user_id),),
    ) or []
    names = [str(r.get("name") or "") for r in rows]
    tokens = ("admin", "manager", "leder", "chef", "teknik", "technician", "support")
    return any(any(token in name for token in tokens) for name in names)


def _ensure_user_exists(user_id: int) -> None:
        user = execute_query_single("SELECT user_id FROM users WHERE user_id = %s", (user_id,))
        if not user:
                raise HTTPException(status_code=404, detail="Bruger ikke fundet")


def _get_next_unassigned_case() -> Optional[dict]:
        return execute_query_single(
                """
                SELECT id, titel, priority
                FROM sag_sager
                WHERE deleted_at IS NULL
                    AND ansvarlig_bruger_id IS NULL
                    AND LOWER(COALESCE(status, '')) NOT IN ('lukket', 'løst', 'closed', 'resolved')
                ORDER BY
                    CASE
                        WHEN LOWER(COALESCE(priority::text, 'normal')) IN ('urgent', 'critical', 'kritisk') THEN 0
                        WHEN LOWER(COALESCE(priority::text, 'normal')) IN ('high', 'høj') THEN 1
                        ELSE 2
                    END,
                    COALESCE(updated_at, created_at) ASC,
                    id ASC
                LIMIT 1
                """
        )

@router.post("/next_task")
async def assign_next_task(
    request: Request,
    user_id: int | None = Query(default=None),
    current_user: dict = Depends(get_current_user),
):
    # Prefer authenticated user context; allow explicit user_id for controlled testing.
    current_user_id = current_user.get("id")
    resolved_user_id = user_id
    if resolved_user_id is None and current_user_id is not None:
        resolved_user_id = int(current_user_id)
    if resolved_user_id is None:
        raise HTTPException(status_code=401, detail="Authentication required for task assignment")

    # Kombinerer de nye services
    router_svc = TaskRouter()
    cal = M365CalendarService()
    
    # Henter hvor meget fri tid medarbejderen har lige nu
    free_mins = await cal.get_user_free_time("now", 2)
    
    # Bed the engine allocate the next best task
    task = await router_svc.get_next_best_task(resolved_user_id)
    task = task or {}
    
    return {
        "status": "assigned",
        "task": task,
        "free_time_calculated": free_mins,
        "message": f"Fandt Næste Opgave (SLA: {task.get('assigned_reason')} - {task.get('estimated_minutes')}m. Du har {free_mins}m frit). "
    }


@router.post("/boss/auto-assign-next")
async def boss_auto_assign_next(current_user: dict = Depends(get_current_user)):
    if not _has_boss_access(current_user):
        raise HTTPException(status_code=403, detail="Insufficient permissions for boss action")

    next_case = _get_next_unassigned_case()
    if not next_case:
        return {
            "status": "noop",
            "message": "Ingen ufordelte åbne sager at fordele.",
        }

    assignee = execute_query_single(
        """
        SELECT
            u.user_id,
            COALESCE(NULLIF(u.full_name, ''), u.username, ('Bruger #' || u.user_id::text)) AS owner_name,
            COUNT(s.id)::int AS open_cases,
            COUNT(CASE WHEN LOWER(COALESCE(s.priority::text, 'normal')) IN ('urgent', 'critical', 'kritisk', 'high', 'høj') THEN 1 END)::int AS hot_cases
        FROM users u
        JOIN user_groups ug ON ug.user_id = u.user_id
        JOIN groups g ON g.id = ug.group_id
        LEFT JOIN sag_sager s
          ON s.ansvarlig_bruger_id = u.user_id
         AND s.deleted_at IS NULL
         AND LOWER(COALESCE(s.status, '')) NOT IN ('lukket', 'løst', 'closed', 'resolved')
        WHERE LOWER(g.name) LIKE ANY(ARRAY['%admin%', '%manager%', '%leder%', '%chef%', '%teknik%', '%technician%', '%support%'])
        GROUP BY u.user_id, u.full_name, u.username
        ORDER BY hot_cases ASC, open_cases ASC, owner_name ASC
        LIMIT 1
        """
    )
    if not assignee:
        raise HTTPException(status_code=409, detail="Ingen kvalificeret medarbejder fundet til auto-fordeling")

    updated = execute_query_single(
        """
        UPDATE sag_sager
        SET ansvarlig_bruger_id = %s,
            updated_at = CURRENT_TIMESTAMP
        WHERE id = %s
        RETURNING id, titel, priority, ansvarlig_bruger_id
        """,
        (int(assignee["user_id"]), int(next_case["id"])),
    )
    if not updated:
        raise HTTPException(status_code=500, detail="Kunne ikke opdatere sag")

    return {
        "status": "assigned",
        "message": "Sagen blev auto-fordelt.",
        "case": {
            "id": updated.get("id"),
            "title": updated.get("titel") or f"Sag #{updated.get('id')}",
            "priority": updated.get("priority") or "normal",
        },
        "assignee": {
            "user_id": assignee.get("user_id"),
            "name": assignee.get("owner_name") or f"Bruger #{assignee.get('user_id')}",
        },
    }


@router.post("/boss/assign-case")
async def boss_assign_case(payload: BossAssignPayload, current_user: dict = Depends(get_current_user)):
    if not _has_boss_access(current_user):
        raise HTTPException(status_code=403, detail="Insufficient permissions for boss action")

    _ensure_user_exists(int(payload.assignee_user_id))

    case_row = execute_query_single(
        """
        SELECT id, titel, priority
        FROM sag_sager
        WHERE id = %s
          AND deleted_at IS NULL
          AND LOWER(COALESCE(status, '')) NOT IN ('lukket', 'løst', 'closed', 'resolved')
        """,
        (int(payload.case_id),),
    )
    if not case_row:
        raise HTTPException(status_code=404, detail="Sag ikke fundet eller er afsluttet")

    updated = execute_query_single(
        """
        UPDATE sag_sager
        SET ansvarlig_bruger_id = %s,
            updated_at = CURRENT_TIMESTAMP
        WHERE id = %s
        RETURNING id, titel, priority, ansvarlig_bruger_id
        """,
        (int(payload.assignee_user_id), int(payload.case_id)),
    )
    if not updated:
        raise HTTPException(status_code=500, detail="Kunne ikke tildele sag")

    return {
        "status": "assigned",
        "message": "Sagen blev tildelt.",
        "case": {
            "id": updated.get("id"),
            "title": updated.get("titel") or f"Sag #{updated.get('id')}",
            "priority": updated.get("priority") or "normal",
        },
        "assignee_user_id": int(payload.assignee_user_id),
    }


@router.post("/boss/assign-next-to-user")
async def boss_assign_next_to_user(payload: BossAssignNextPayload, current_user: dict = Depends(get_current_user)):
    if not _has_boss_access(current_user):
        raise HTTPException(status_code=403, detail="Insufficient permissions for boss action")

    _ensure_user_exists(int(payload.assignee_user_id))

    next_case = _get_next_unassigned_case()
    if not next_case:
        return {
            "status": "noop",
            "message": "Ingen ufordelte åbne sager at tildele.",
        }

    updated = execute_query_single(
        """
        UPDATE sag_sager
        SET ansvarlig_bruger_id = %s,
            updated_at = CURRENT_TIMESTAMP
        WHERE id = %s
        RETURNING id, titel, priority, ansvarlig_bruger_id
        """,
        (int(payload.assignee_user_id), int(next_case["id"])),
    )
    if not updated:
        raise HTTPException(status_code=500, detail="Kunne ikke tildele næste sag")

    return {
        "status": "assigned",
        "message": "Næste ufordelte sag blev tildelt.",
        "case": {
            "id": updated.get("id"),
            "title": updated.get("titel") or f"Sag #{updated.get('id')}",
            "priority": updated.get("priority") or "normal",
        },
        "assignee_user_id": int(payload.assignee_user_id),
    }
