# -*- coding: utf-8 -*-
"""STEP 8 — Discovery + subpoena (Rule 12.351 objection-window gate + routing).

A discovery request hangs off a PROCEEDING. The headline safety feature is the
NON-PARTY PRODUCTION (Rule 12.351) objection-window gate:

  Before a Rule 12.351 subpoena for production from a non-party may be ISSUED, the
  requesting party must serve notice on the other parties and wait out the objection
  window (10 days). The subpoena CANNOT be issued until that window has elapsed AND
  no objection is pending. This is a HARD gate, enforced in code.

Issuance ROUTING depends on representation (Forms & Playbook, Part C):
  * attorney of record -> issues directly (officer of the court)
  * pro se -> the CLERK issues the subpoena
On issuance, a Notice of Issuance must be served the SAME DAY.

VERIFY current rule — Rule 12.410 (subpoenas) was amended effective Oct 1 2025;
confirm the objection window and notice mechanics before relying in production.
"""

from datetime import timedelta

from odoo import api, fields, models, _
from odoo.exceptions import UserError

OBJECTION_DAYS = 10          # Rule 12.351 notice/objection window — VERIFY
RESPONSE_DAYS = 30           # typical production response window — VERIFY


def _roll(due):
    while due.weekday() >= 5:
        due += timedelta(days=1)
    return due


class FamilyLawDiscoveryRequest(models.Model):
    _name = "familylaw.discovery.request"
    _description = "Discovery Request / Subpoena"
    _inherit = ["mail.thread", "mail.activity.mixin"]
    _order = "create_date desc"

    name = fields.Char(required=True, tracking=True)
    proceeding_id = fields.Many2one(
        "familylaw.proceeding", required=True, ondelete="cascade", index=True,
        tracking=True,
    )
    case_id = fields.Many2one(
        "familylaw.case", related="proceeding_id.case_id", store=True, index=True,
    )
    representation = fields.Selection(
        related="case_id.representation", store=True, string="Representation",
    )
    discovery_type = fields.Selection(
        selection=[
            ("interrogatories", "Interrogatories"),
            ("production", "Request for Production (party)"),
            ("admissions", "Requests for Admission"),
            ("nonparty_production", "Non-Party Production — Rule 12.351"),
            ("deposition", "Deposition"),
        ],
        string="Type",
        required=True,
        default="production",
        tracking=True,
    )
    is_nonparty = fields.Boolean(compute="_compute_is_nonparty", store=True)
    nonparty_name = fields.Char(string="Non-Party (subpoena target)")

    issuance_route = fields.Selection(
        selection=[
            ("attorney_direct", "Attorney issues directly"),
            ("clerk", "Clerk issues (pro se)"),
        ],
        compute="_compute_issuance_route",
        store=True,
        string="Issuance Route",
    )

    # Rule 12.351 objection window
    notice_served_date = fields.Date(
        string="Notice to Parties Served",
        tracking=True,
        help="Starts the Rule 12.351 objection window.",
    )
    objection_deadline = fields.Date(
        compute="_compute_objection_deadline", store=True,
    )
    objection_received = fields.Boolean(string="Objection Received", tracking=True)
    objection_note = fields.Text()

    state = fields.Selection(
        selection=[
            ("draft", "Draft"),
            ("notice_served", "Notice Served"),
            ("issued", "Issued"),
            ("responded", "Responded"),
            ("objected", "Objected"),
        ],
        default="draft",
        required=True,
        tracking=True,
    )
    issuance_date = fields.Date(string="Issued On", readonly=True, copy=False)
    notice_of_issuance_date = fields.Date(
        string="Notice of Issuance Served", readonly=True, copy=False,
        help="Must be served the same day the subpoena issues.",
    )
    response_due_date = fields.Date(compute="_compute_response_due", store=True)

    @api.depends("discovery_type")
    def _compute_is_nonparty(self):
        for r in self:
            r.is_nonparty = r.discovery_type == "nonparty_production"

    @api.depends("representation")
    def _compute_issuance_route(self):
        for r in self:
            r.issuance_route = (
                "attorney_direct" if r.representation == "attorney" else "clerk"
            )

    @api.depends("notice_served_date")
    def _compute_objection_deadline(self):
        for r in self:
            if r.notice_served_date:
                r.objection_deadline = _roll(
                    r.notice_served_date + timedelta(days=OBJECTION_DAYS)
                )
            else:
                r.objection_deadline = False

    @api.depends("issuance_date")
    def _compute_response_due(self):
        for r in self:
            if r.issuance_date:
                r.response_due_date = _roll(
                    r.issuance_date + timedelta(days=RESPONSE_DAYS)
                )
            else:
                r.response_due_date = False

    # --- workflow -----------------------------------------------------------
    def action_serve_notice(self):
        for r in self:
            if not r.notice_served_date:
                r.notice_served_date = fields.Date.context_today(r)
            r.state = "notice_served"
            r.message_post(body=_("Notice to other parties served (Rule 12.351). "
                                  "Objection window runs to %s.") % r.objection_deadline)
        return True

    def _ensure_objection_window_elapsed(self):
        """HARD gate for Rule 12.351 non-party subpoenas."""
        today = fields.Date.context_today(self)
        for r in self:
            if not r.is_nonparty:
                continue
            if not r.notice_served_date:
                raise UserError(
                    _("Cannot issue a Rule 12.351 non-party subpoena before serving "
                      "notice on the other parties and running the objection window.")
                )
            if r.objection_received:
                raise UserError(
                    _("An objection is pending on '%s'. The subpoena cannot be issued "
                      "until the objection is resolved by the court.") % r.name
                )
            if not r.objection_deadline or today < r.objection_deadline:
                raise UserError(
                    _("The Rule 12.351 objection window has not elapsed (runs to %s). "
                      "The non-party subpoena cannot be issued yet.")
                    % r.objection_deadline
                )

    def action_record_objection(self):
        for r in self:
            r.objection_received = True
            r.state = "objected"
            r.message_post(body=_("Objection recorded — issuance blocked pending "
                                  "court resolution."))
        return True

    def action_issue(self):
        """Issue the subpoena/request. Enforces the 12.351 objection gate for
        non-party production and serves the Notice of Issuance the SAME DAY."""
        self._ensure_objection_window_elapsed()
        today = fields.Date.context_today(self)
        for r in self:
            r.write({
                "state": "issued",
                "issuance_date": today,
                "notice_of_issuance_date": today,  # same-day requirement
            })
            route = dict(r._fields["issuance_route"].selection).get(r.issuance_route)
            r.message_post(body=_("Issued (%(route)s). Notice of Issuance served "
                                  "same day. Response due %(due)s.",
                                  route=route, due=r.response_due_date))
        return True

    def action_mark_responded(self):
        for r in self:
            r.state = "responded"
            r.message_post(body=_("Response received."))
        return True
