#!/usr/bin/env python3
"""Day-count checks for the 183-day / six-year piece.

Rules under test (all verbatim sources in the article):
  A. 个人所得税法 art.1  — resident if domiciled, or 183+ days inside China in a tax year.
  B. 财政部 税务总局公告2019年第34号 art.2 — only days where the person spent a
     full 24 hours inside China count; a partial day does not.
  C. 实施条例 art.4 — the six-year run restarts if any of the qualifying years
     contains a single absence longer than 30 days.
  D. 34号公告 art.1 — the six-year window is the six consecutive years before the
     year in question, and the count starts at 2019.

This file computes the three things the article prints:
  1. the weekly commute arithmetic reproduced from the official Q&A (3 days/week x 52
     = 156 days);
  2. a naive counter (every calendar day touched) versus rule B for the same trips;
  3. the first year at risk of worldwide taxation for several stay profiles, plus how
     long a sub-183-day year postpones that year.
"""
from datetime import date

# ---------- 1. the official worked example, reproduced ----------
# Q&A (2019-03-16): arrives Monday morning, leaves Friday evening.
# Monday and Friday are partial; Saturday and Sunday are not in China at all.
week_days_counted = 3            # Tue, Wed, Thu
weeks = 52
annual = week_days_counted * weeks
assert annual == 156, annual
assert annual < 183
print(f"[1] 3 countable days x 52 weeks = {annual} days -> under 183: {annual < 183}")

# ---------- 2. naive vs rule B on individual trips ----------
def days_rule_b(arrive: date, leave: date, full_days: int) -> int:
    """Rule B: count only days spent wholly inside China.

    arrive/leave are the boundary days; `full_days` is the number of complete
    calendar days between them that are spent entirely inside China.
    """
    return full_days

def days_naive(arrive: date, leave: date, full_days: int) -> int:
    """Every calendar day touched, boundary days included (the treaty habit)."""
    return full_days + 2

trips = [
    ("Mon 08:00 in, Fri 19:00 out", date(2026, 3, 2), date(2026, 3, 6), 3),
    ("Sat in, Sun out", date(2026, 3, 7), date(2026, 3, 8), 0),
    ("1 May in, 2 June out (one long stay)", date(2026, 5, 1), date(2026, 6, 2), 31),
]
print("\n[2] same trip, two counters")
for label, a, l, full in trips:
    b = days_rule_b(a, l, full)
    n = days_naive(a, l, full)
    print(f"    {label:<38} ruleB={b:>4}  naive={n:>4}  diff={n - b}")

# ---------- 3. six-year window ----------
def worldwide_tax_year(first_qualifying: int, absences_over_30: set[int],
                       sub183_years: set[int], last: int = 2040) -> int | None:
    """First tax year in which worldwide income is taxable.

    A year qualifies when the person is inside China 183+ days and did not have a
    single absence longer than 30 days in it. Worldwide tax applies in year Y when
    Y itself qualifies and the six years before Y all qualify.
    """
    def qualifies(y: int) -> bool:
        return y >= first_qualifying and y not in sub183_years and y not in absences_over_30

    for y in range(first_qualifying, last + 1):
        if qualifies(y) and all(qualifies(y - k) for k in range(1, 7)):
            return y
    return None

profiles = [
    ("arrived 2019, never away >30 days", 2019, set(), set()),
    ("arrived 2019, exactly 30 days away in 2022", 2019, set(), set()),
    ("arrived 2019, 31-day absence in 2022", 2019, {2022}, set()),
    ("arrived 2019, one 170-day year in 2024", 2019, set(), {2024}),
    ("arrived 2021, never away >30 days", 2021, set(), set()),
]
print("\n[3] first year of worldwide taxation")
for label, start, absences, sub in profiles:
    y = worldwide_tax_year(start, absences, sub)
    print(f"    {label:<40} -> {y}")

# a sub-183 year postpones the first worldwide year by exactly six years
base = worldwide_tax_year(2019, set(), set())
shifted = worldwide_tax_year(2019, set(), {2024})
assert base == 2025, base
assert shifted == 2031, shifted
assert shifted - base == 6
print(f"    delay from one 170-day year: {shifted - base} years")

# 2026 window check: the six years before 2026 are 2020-2025
window_2026 = [2026 - k for k in range(1, 7)]
assert window_2026 == [2025, 2024, 2023, 2022, 2021, 2020]
print(f"    window for 2026: {sorted(window_2026)}")

# 30 days vs "more than 30": 30 days is not enough to reset
for gap, resets in ((30, False), (31, True)):
    print(f"    absence of {gap} days resets the run: {resets}")
    assert resets == (gap > 30)

# ---------- 4. share of the year ----------
print(f"\n[4] 183 / 365 = {183 / 365:.4f}")
