"""
HABITS — Phase 7, and the slice whose most important field does not exist.

The contract is `front/src/renderer/src/features/habits/data/api.js` and the
field set is `features/habits/model.js`. Where this file disagrees with either,
this file is wrong.

**THERE IS NO `streak_count` COLUMN, AND THERE MUST NOT BE ONE.** `Lifey.md`'s
entity sketch lists one; that sketch is wrong here, and the reason is the
commonest edit a habit tracker gets. A streak is a function of the log AND of
the schedule, and filling in a day you forgot has to REPAIR it — which it only
can if the streak is derived. A stored counter has to be rewritten on every
edit to any earlier day, and the first time one of those rewrites is missed the
number is silently wrong with nothing to check it against. The server may
compute one for its own queries; it stores none, and `data/api.js` says it will
not trust one if it arrives.

Four more things this model states deliberately:

1. **`log` IS ONE JSON MAP, `{'yyyy-MM-dd': count}`.** Not a `HabitLog` table
   with a row per day. A day's entry has no identity outside its habit, nothing
   links to one, and the operation it gets most is "read the last ninety days
   at once" — one column read against JSON, ninety rows against a table. A year
   of daily logging is about 4 KB.

   **THE DAY KEYS ARE STORED VERBATIM.** They are local wall-clock days, never
   timestamps — the same "a date is a day" rule `lib/dates.js` sets out.
   Re-interpreting them in UTC moves somebody's whole history by a day, in one
   direction for half the world.

2. **A LOG IS A COUNT PER DAY, NOT A BOOLEAN**, and `target` is why. The
   frame's own mock data forces it: two of its habits are called "Read 30 pages
   a day" and "Brush your teeth 2 times", which is a quantity smuggled into a
   NAME because the wireframe has no field for one. A boolean would leave
   "2 of 3 glasses" unrepresentable and push every user into naming their way
   around it.

3. **`schedule` IS ONE JSON FIELD, `{kind, days, timesPerWeek}`**, not three
   columns — two of the three are only meaningful for one kind, and three
   nullable columns is a shape that lets an impossible schedule be stored. The
   kinds are `daily`, `weekdays` (days outside the set are OFF: not done, not
   missed, nothing was expected) and `weekly` (**the streak unit is the WEEK**,
   which is the whole point of the kind).

4. **`archived` IS NOT `deleted`.** Stopping a habit must not throw away the
   weeks you did keep it, and an archived habit still counts in the statistics.

`HISTORY_DAYS` is the beta's 92-day window, matching `features/habits/csv.js`.
It is enforced by the serializer on write, not by the column — see there.
"""

from django.db import models

from core.models import TimeStampedModel

from .workspace import Page

# `SCHEDULE_KINDS` in `features/habits/model.js`.
SCHEDULE_KINDS = ('daily', 'weekdays', 'weekly')

# Days of history the beta keeps — `HISTORY_DAYS` in `features/habits/csv.js`.
# The client's CSV export already covers exactly this window, so a server that
# kept more would export less than it holds and read as losing days.
HISTORY_DAYS = 92

# The schedule every habit falls back to. `scheduleOf` produces this exact
# object for a missing or malformed one, and "every day" is the reading that
# never hides a day from the user.
DEFAULT_SCHEDULE = {'kind': 'daily', 'days': [1, 2, 3, 4, 5], 'timesPerWeek': 3}


class Habit(TimeStampedModel):
    page = models.ForeignKey(Page, on_delete=models.CASCADE, related_name='habits')

    title = models.CharField(max_length=300, blank=True)
    notes = models.TextField(blank=True)

    # A lucide id string (`'lucide:Footprints'`), not the `{id, color}` pair a
    # note's icon is — Habits carries the colour in its own column, because the
    # colour is the habit's identity in the grid and in every chart.
    icon = models.CharField(max_length=64, null=True, blank=True)
    color = models.CharField(max_length=16, null=True, blank=True)

    # Tag IDS, against the page-scoped vocabulary in that page's settings blob.
    tags = models.JSONField(default=list, blank=True)

    schedule = models.JSONField(default=dict, blank=True)

    # How many of `unit` count as a day done. 1 with an empty unit is a tick.
    target = models.IntegerField(default=1)
    unit = models.CharField(max_length=32, blank=True)

    # `{'yyyy-MM-dd': count}`. See the module docstring.
    log = models.JSONField(default=dict, blank=True)

    archived = models.BooleanField(default=False)

    properties = models.JSONField(default=dict, blank=True)

    is_sample = models.BooleanField(default=False)

    class Meta:
        ordering = ['id']
        indexes = [
            # The grid hides archived habits until asked, which is the one
            # filter this table has.
            models.Index(fields=['page', 'archived']),
        ]

    def __str__(self):
        return self.title or f'(untitled habit {self.pk})'
