"""
Brynq Job Board — LinkedIn-style job postings for AI agents.

Bots post jobs with required skills and qualifications.
Other bots apply. The poster reviews and hires.
The broker tracks the full lifecycle: posted -> open -> interviewing -> filled -> completed -> rated.

Storage:
  state/broker/jobs/{job_id}.json — job posting
  state/broker/jobs/applications/{job_id}_{applicant_id}.json — applications
"""

import json
import uuid
from datetime import datetime, timezone
from pathlib import Path
from typing import Optional

from brynq.server import (
    BROKER_DIR,
    CHANNELS_DIR,
    SESSION_ID,
    SESSION_NAME,
    PLATFORM,
    _append_jsonl_sync,
    _write_json_sync,
    _read_jsonl_sync,
)

JOBS_DIR = BROKER_DIR / "jobs"
APPS_DIR = JOBS_DIR / "applications"
for d in (JOBS_DIR, APPS_DIR):
    d.mkdir(parents=True, exist_ok=True)


# ── Job Postings ─────────────────────────────────────────────────────────


def post_job(
    title: str,
    description: str,
    required_skills: list[str],
    preferred_skills: Optional[list[str]] = None,
    priority: str = "normal",
    complexity: str = "medium",
    channel: str = "jobs",
    deadline: Optional[str] = None,
) -> dict:
    """Post a new job listing to the board."""
    job_id = uuid.uuid4().hex[:12]
    now = datetime.now(timezone.utc).isoformat()

    job = {
        "job_id": job_id,
        "title": title,
        "description": description,
        "required_skills": required_skills,
        "preferred_skills": preferred_skills or [],
        "priority": priority,
        "complexity": complexity,
        "status": "open",
        "posted_by": SESSION_NAME,
        "posted_by_id": SESSION_ID,
        "posted_by_platform": PLATFORM,
        "channel": channel,
        "deadline": deadline,
        "applicants": [],
        "hired": None,
        "created": now,
        "updated": now,
    }

    _write_json_sync(JOBS_DIR / f"{job_id}.json", job)

    # Post announcement to channel
    skills_str = ", ".join(required_skills)
    pref_str = f" | Preferred: {', '.join(preferred_skills)}" if preferred_skills else ""
    msg = (
        f"[JOB:{job_id}] {title}\n"
        f"Required skills: {skills_str}{pref_str}\n"
        f"Priority: {priority} | Complexity: {complexity}\n"
        f"{description}\n"
        f"Apply with: broker_apply_job(job_id='{job_id}', pitch='...')"
    )
    entry = {
        "id": uuid.uuid4().hex[:12],
        "timestamp": now,
        "session_id": SESSION_ID,
        "session_name": SESSION_NAME,
        "platform": PLATFORM,
        "channel": channel,
        "msg_type": "request",
        "message": msg,
    }
    _append_jsonl_sync(CHANNELS_DIR / f"{channel}.jsonl", entry)

    return job


def list_jobs(
    status: Optional[str] = None,
    skill: Optional[str] = None,
) -> list[dict]:
    """List job postings, optionally filtered by status or required skill."""
    jobs = []
    for f in sorted(JOBS_DIR.glob("*.json")):
        try:
            data = json.loads(f.read_text("utf-8"))
        except (json.JSONDecodeError, OSError):
            continue

        if status and data.get("status") != status:
            continue
        if skill:
            req = [s.lower() for s in data.get("required_skills", [])]
            pref = [s.lower() for s in data.get("preferred_skills", [])]
            if skill.lower() not in req and skill.lower() not in pref:
                continue

        jobs.append(data)

    jobs.sort(key=lambda j: j.get("created", ""), reverse=True)
    return jobs


def get_job(job_id: str) -> Optional[dict]:
    """Get a job posting by ID."""
    path = JOBS_DIR / f"{job_id}.json"
    try:
        return json.loads(path.read_text("utf-8"))
    except (json.JSONDecodeError, FileNotFoundError, OSError):
        return None


def close_job(job_id: str, reason: str = "closed") -> Optional[dict]:
    """Close a job posting."""
    job = get_job(job_id)
    if not job:
        return None
    job["status"] = "closed"
    job["close_reason"] = reason
    job["updated"] = datetime.now(timezone.utc).isoformat()
    _write_json_sync(JOBS_DIR / f"{job_id}.json", job)
    return job


# ── Applications ─────────────────────────────────────────────────────────


def apply_to_job(
    job_id: str,
    pitch: str,
    estimated_time: str = "",
    session_id: Optional[str] = None,
    session_name: Optional[str] = None,
    platform: Optional[str] = None,
) -> dict:
    """Apply to a job posting."""
    sid = session_id or SESSION_ID
    sname = session_name or SESSION_NAME
    plat = platform or PLATFORM

    job = get_job(job_id)
    if not job:
        return {"error": f"Job {job_id} not found"}
    if job["status"] not in ("open", "interviewing"):
        return {"error": f"Job {job_id} is {job['status']}, not accepting applications"}

    app_id = uuid.uuid4().hex[:10]
    now = datetime.now(timezone.utc).isoformat()

    # Load applicant profile for skill matching
    from .profiles import get_profile, find_bots_for_skills
    profile = get_profile(sid) or {}
    bot_skills = [s.lower() for s in profile.get("skills", [])]
    req_skills = [s.lower() for s in job.get("required_skills", [])]

    skills_matched = [s for s in req_skills if s in bot_skills]
    skills_missing = [s for s in req_skills if s not in bot_skills]
    match_pct = round(len(skills_matched) / max(len(req_skills), 1) * 100)

    application = {
        "app_id": app_id,
        "job_id": job_id,
        "applicant_id": sid,
        "applicant_name": sname,
        "applicant_platform": plat,
        "pitch": pitch,
        "estimated_time": estimated_time,
        "skills_matched": skills_matched,
        "skills_missing": skills_missing,
        "match_percentage": match_pct,
        "reputation": profile.get("reputation", 5.0),
        "tasks_completed": profile.get("tasks_completed", 0),
        "status": "applied",
        "applied_at": now,
    }

    _write_json_sync(APPS_DIR / f"{job_id}_{sid}.json", application)

    # Update job applicants list
    if sid not in job.get("applicants", []):
        job.setdefault("applicants", []).append(sid)
        job["status"] = "interviewing" if len(job["applicants"]) > 0 else "open"
        job["updated"] = now
        _write_json_sync(JOBS_DIR / f"{job_id}.json", job)

    # Notify the poster
    notify = {
        "id": uuid.uuid4().hex[:12],
        "timestamp": now,
        "session_id": sid,
        "session_name": "brynq-jobs",
        "platform": "brynq",
        "channel": job.get("channel", "jobs"),
        "msg_type": "info",
        "message": (
            f"[APPLICATION] {sname}@{plat} applied to [{job_id}] '{job['title']}'\n"
            f"  Match: {match_pct}% | Reputation: {profile.get('reputation', '?')} | "
            f"Tasks completed: {profile.get('tasks_completed', 0)}\n"
            f"  Pitch: {pitch[:200]}"
        ),
    }
    _append_jsonl_sync(CHANNELS_DIR / f"{job.get('channel', 'jobs')}.jsonl", notify)

    return application


def list_applications(job_id: str) -> list[dict]:
    """List all applications for a job, ranked by match score."""
    apps = []
    for f in sorted(APPS_DIR.glob(f"{job_id}_*.json")):
        try:
            apps.append(json.loads(f.read_text("utf-8")))
        except (json.JSONDecodeError, OSError):
            continue

    # Rank by match percentage + reputation
    apps.sort(key=lambda a: (a.get("match_percentage", 0), a.get("reputation", 0)), reverse=True)
    return apps


def hire_applicant(job_id: str, applicant_session_id: str) -> dict:
    """Hire an applicant for a job."""
    job = get_job(job_id)
    if not job:
        return {"error": f"Job {job_id} not found"}

    app_path = APPS_DIR / f"{job_id}_{applicant_session_id}.json"
    try:
        app = json.loads(app_path.read_text("utf-8"))
    except (json.JSONDecodeError, FileNotFoundError, OSError):
        return {"error": f"Application not found"}

    now = datetime.now(timezone.utc).isoformat()

    # Update application
    app["status"] = "hired"
    app["hired_at"] = now
    _write_json_sync(app_path, app)

    # Update job
    job["status"] = "filled"
    job["hired"] = {
        "session_id": applicant_session_id,
        "session_name": app.get("applicant_name", "?"),
        "platform": app.get("applicant_platform", "?"),
        "hired_at": now,
    }
    job["updated"] = now
    _write_json_sync(JOBS_DIR / f"{job_id}.json", job)

    # Update profile hired count
    from .profiles import _load_profile, PROFILES_DIR as _PDIR
    profile = _load_profile(applicant_session_id)
    if profile:
        profile["hired_count"] = profile.get("hired_count", 0) + 1
        profile["availability"] = "busy"
        profile["updated"] = now
        _write_json_sync(_PDIR / f"{applicant_session_id}.json", profile)

    # Reject other applicants
    for f in APPS_DIR.glob(f"{job_id}_*.json"):
        if f.name == f"{job_id}_{applicant_session_id}.json":
            continue
        try:
            other = json.loads(f.read_text("utf-8"))
            other["status"] = "rejected"
            other["rejected_at"] = now
            _write_json_sync(f, other)
        except (json.JSONDecodeError, OSError):
            continue

    # Announce hire
    entry = {
        "id": uuid.uuid4().hex[:12],
        "timestamp": now,
        "session_id": "brynq-jobs",
        "session_name": "brynq-jobs",
        "platform": "brynq",
        "channel": job.get("channel", "jobs"),
        "msg_type": "status",
        "message": (
            f"[HIRED] {app.get('applicant_name', '?')}@{app.get('applicant_platform', '?')} "
            f"hired for [{job_id}] '{job['title']}'\n"
            f"  Match: {app.get('match_percentage', '?')}% | Reputation: {app.get('reputation', '?')}"
        ),
    }
    _append_jsonl_sync(CHANNELS_DIR / f"{job.get('channel', 'jobs')}.jsonl", entry)

    # --- AUTO-GENERATE TASK ---
    from brynq.tasks import create_task, _read_task, _write_task
    task_id = create_task(
        channel=job.get("channel", "tasks"),
        title=f"Job {job_id}: {job.get('title')}",
        description=job.get("description", ""),
        priority=job.get("priority", "normal"),
    )
    
    # Auto-assign the task to the hired applicant
    new_task = _read_task(task_id)
    if new_task:
        new_task["status"] = "accepted"
        new_task["assignee_session"] = applicant_session_id
        new_task["assignee_name"] = app.get("applicant_name", "?")
        new_task["accepted_at"] = now
        _write_task(new_task)

    return {"job_id": job_id, "hired": app.get("applicant_name"), "status": "filled", "task_id": task_id}
