"""Modal dialog for booking a mock interview."""

from datetime import datetime, timedelta, timezone

import httpx
from textual import work
from textual.app import ComposeResult
from textual.binding import Binding
from textual.containers import Container, Horizontal
from textual.screen import ModalScreen
from textual.widgets import Button, Input, Label, Select, Static

INTERVIEW_TYPE_OPTIONS = [
    ("Behavioral", "behavioral"),
    ("Technical Coding", "technical_coding"),
    ("System Design", "system_design"),
    ("Product Sense", "product_sense"),
    ("Analytical", "analytical"),
    ("Case Study", "case_study"),
    ("Portfolio Review", "portfolio_review"),
    ("Role Play", "role_play"),
]

# Detect local timezone offset for display.
_LOCAL_TZ = datetime.now().astimezone().tzinfo
_LOCAL_TZ_NAME = datetime.now().astimezone().strftime("%Z")  # e.g. "EDT", "PST"


def _date_options() -> list[tuple[str, str]]:
    """Generate date options for the next 14 days in local time.

    Returns (display_label, iso_date_str) tuples.
    Display: "Wed Apr  3" / "Today" / "Tomorrow".
    Value: "2026-04-03" (local date).
    """
    now_local = datetime.now().astimezone()
    today = now_local.date()
    options: list[tuple[str, str]] = []
    for i in range(14):
        d = today + timedelta(days=i)
        if i == 0:
            label = f"Today — {d.strftime('%a %b %d')}"
        elif i == 1:
            label = f"Tomorrow — {d.strftime('%a %b %d')}"
        else:
            label = d.strftime("%a %b %d")
        options.append((label, d.isoformat()))
    return options


def _time_options(selected_date: str | None = None) -> list[tuple[str, str]]:
    """Generate 30-minute time slot options, filtering out past times for today.

    Args:
        selected_date: ISO date string (e.g. "2026-04-03"). If today,
            slots before the current time are excluded.

    Returns (display_label, HH:MM) tuples.
    Display: "9:00 AM", "9:30 AM", etc.
    Value: "09:00", "09:30", etc.
    """
    now_local = datetime.now().astimezone()
    is_today = selected_date == now_local.date().isoformat() if selected_date else False

    options: list[tuple[str, str]] = []
    for hour in range(24):
        for minute in (0, 30):
            if is_today and (hour < now_local.hour or (hour == now_local.hour and minute <= now_local.minute)):
                continue
            t = datetime(2000, 1, 1, hour, minute)
            label = t.strftime("%I:%M %p").lstrip("0")
            value = f"{hour:02d}:{minute:02d}"
            options.append((label, value))
    return options


def _default_date() -> str:
    """Today's local date, or tomorrow if no time slots remain today."""
    now_local = datetime.now().astimezone()
    if _time_options(selected_date=now_local.date().isoformat()):
        return now_local.date().isoformat()
    return (now_local.date() + timedelta(days=1)).isoformat()


def _default_time_slot() -> str:
    """Next 30-min slot at least 1 hour from now, as HH:MM."""
    now = datetime.now().astimezone() + timedelta(hours=1)
    if now.minute < 30:
        return f"{now.hour:02d}:30"
    else:
        next_hour = (now.hour + 1) % 24
        return f"{next_hour:02d}:00"


class InterviewBookModal(ModalScreen[bool]):
    """Collects interview parameters and books via the API."""

    BINDINGS = [
        Binding("escape", "cancel", "Cancel", show=False),
    ]

    DEFAULT_CSS = """
    InterviewBookModal {
        align: center middle;
        background: $surface 80%;
    }

    #interview-modal-container {
        width: 64;
        height: auto;
        border: round $accent;
        padding: 1 2;
        background: $surface;
    }

    #interview-modal-title {
        text-align: center;
        padding: 0 0 1 0;
    }

    #interview-modal-error {
        color: $error;
        height: auto;
        padding: 0 0 1 0;
    }

    .iv-field-label {
        padding: 0 0 0 0;
        height: 1;
    }

    #iv-role-input,
    #iv-invite-input,
    #iv-company-input,
    #iv-link-input {
        margin: 0 0 1 0;
    }

    #iv-type-select,
    #iv-date-select,
    #iv-time-select {
        margin: 0 0 1 0;
    }

    #iv-buttons {
        padding: 1 0 0 0;
        align: center middle;
    }

    #iv-book-btn {
        margin: 0 1 0 0;
    }
    """

    def __init__(self, *, client) -> None:
        super().__init__()
        self.client = client

    def compose(self) -> ComposeResult:
        with Container(id="interview-modal-container"):
            yield Static("[bold]Book Mock Interview[/bold]", id="interview-modal-title")
            yield Label("Role title (required)", classes="iv-field-label")
            yield Input(
                placeholder="e.g. Senior Software Engineer",
                id="iv-role-input",
            )
            yield Label("Interview type", classes="iv-field-label")
            yield Select(
                INTERVIEW_TYPE_OPTIONS,
                id="iv-type-select",
                allow_blank=False,
                value="behavioral",
            )
            yield Label(f"Date ({_LOCAL_TZ_NAME})", classes="iv-field-label")
            yield Select(
                _date_options(),
                id="iv-date-select",
                allow_blank=False,
                value=_default_date(),
            )
            yield Label(f"Time ({_LOCAL_TZ_NAME})", classes="iv-field-label")
            yield Select(
                _time_options(selected_date=_default_date()),
                id="iv-time-select",
                allow_blank=False,
                value=_default_time_slot(),
            )
            yield Label("Invite code (required)", classes="iv-field-label")
            yield Input(
                placeholder="e.g. ABC123",
                id="iv-invite-input",
            )
            yield Label("Company slug (optional)", classes="iv-field-label")
            yield Input(
                placeholder="e.g. google, anthropic",
                id="iv-company-input",
            )
            yield Label("Meeting link (optional)", classes="iv-field-label")
            yield Input(
                placeholder="e.g. https://zoom.us/j/...",
                id="iv-link-input",
            )
            yield Static("", id="interview-modal-error")
            with Horizontal(id="iv-buttons"):
                yield Button("Book", id="iv-book-btn", variant="primary")
                yield Button("Cancel", id="iv-cancel-btn")

    def on_select_changed(self, event: Select.Changed) -> None:
        """When the date changes, refresh time options to filter past slots."""
        if event.select.id == "iv-date-select":
            time_select = self.query_one("#iv-time-select", Select)
            new_options = _time_options(selected_date=str(event.value))
            if not new_options:
                # All slots for this date are past — show all 48 (submit validates)
                new_options = _time_options()
            time_select.set_options(new_options)

    def on_button_pressed(self, event: Button.Pressed) -> None:
        if event.button.id == "iv-cancel-btn":
            self.dismiss(False)
        elif event.button.id == "iv-book-btn":
            self._submit()

    def _submit(self) -> None:
        error_widget = self.query_one("#interview-modal-error", Static)
        error_widget.update("")

        role = self.query_one("#iv-role-input", Input).value.strip()
        if not role:
            error_widget.update("Role title is required.")
            return

        interview_type = self.query_one("#iv-type-select", Select).value

        date_str = self.query_one("#iv-date-select", Select).value
        time_str = self.query_one("#iv-time-select", Select).value

        # Combine date + time in local timezone, then convert to UTC.
        local_dt = datetime.fromisoformat(f"{date_str}T{time_str}:00").replace(
            tzinfo=_LOCAL_TZ
        )
        if local_dt < datetime.now().astimezone():
            error_widget.update("Scheduled time must be in the future.")
            return
        utc_dt = local_dt.astimezone(timezone.utc)
        scheduled_at = utc_dt.strftime("%Y-%m-%dT%H:%M:%SZ")

        invite_code = self.query_one("#iv-invite-input", Input).value.strip().upper()
        if not invite_code:
            error_widget.update("Invite code is required.")
            return

        company = self.query_one("#iv-company-input", Input).value.strip()
        link = self.query_one("#iv-link-input", Input).value.strip()

        self._do_book(role, interview_type, scheduled_at, invite_code, company, link)

    @work(thread=True, exit_on_error=False)
    def _do_book(
        self,
        role: str,
        interview_type: str,
        scheduled_at: str,
        invite_code: str,
        company: str,
        link: str,
    ) -> None:
        try:
            self.client.create_interview(
                role_title=role,
                interview_type=interview_type,
                scheduled_at=scheduled_at,
                invite_code=invite_code,
                company_slug=company,
                meeting_link=link,
            )
        except httpx.HTTPStatusError as exc:
            status = exc.response.status_code
            if status == 403:
                msg = "Invalid, expired, or already used invite code."
            elif status == 409:
                body = exc.response.text
                if "capacity" in body:
                    msg = "Time slot is full — try a different time."
                elif "pending" in body:
                    msg = "You have 3 pending interviews — complete or cancel one first."
                else:
                    msg = "Booking conflict. Try again."
            elif status == 400:
                try:
                    detail = exc.response.json().get("error", "")
                    msg = f"Invalid request: {detail}" if detail else "Invalid request."
                except Exception:
                    msg = "Invalid request."
            else:
                msg = f"Failed to book interview (HTTP {status})."
            self.app.call_from_thread(
                self.query_one("#interview-modal-error", Static).update, msg
            )
            return
        except Exception:
            self.app.call_from_thread(
                self.query_one("#interview-modal-error", Static).update,
                "Something went wrong. Please try again.",
            )
            return
        self.app.call_from_thread(self.dismiss, True)

    def action_cancel(self) -> None:
        self.dismiss(False)
