"""Operational counts and existing-ledger totals, never accounting profit."""
from datetime import date
from fastapi import Request,Query
from .store import many
from .documents import invoice_rows
from .workflow import pipeline,queue,today,local_day,fail
from .workflow_models import calendar_day
from .current_positions import open_job, open_quote_state

def report(db,start,end):
    try:
        calendar_day(start);calendar_day(end)
        if not 0<=(date.fromisoformat(end)-date.fromisoformat(start)).days<=365:raise ValueError()
    except (ValueError,TypeError):fail('Choose an inclusive period of at most 366 UK dates.',422)
    inside=lambda day:bool(day) and start<=day<=end
    jobs=pipeline(db,archive='all')['jobs'];by_id={j['id']:j for j in jobs}
    customers=many(db,'SELECT id,created_at FROM customers')
    quotes=many(db,"SELECT q.*,l.current,json_extract(q.snapshot,'$.valid_until') AS valid_until FROM quotes q JOIN quote_links l ON l.quote_id=q.id")
    inv=invoice_rows(db);issued=[i for i in inv if i['status']=='issued']
    receipts=many(db,'SELECT p.amount_pence,d.paid_on FROM payments p JOIN payment_details d ON d.payment_id=p.id WHERE p.id NOT IN (SELECT payment_id FROM payment_reversals)')
    current=today()
    estimate=[q for q in quotes if open_quote_state(q,by_id[q['job_id']]['status'],by_id[q['job_id']]['workflow']['archived'],current)=='included']
    labour=sum(r['cost_pence'] for r in many(db,'SELECT cost_pence,work_date FROM time_entries WHERE archived=0') if inside(r['work_date']))
    materials=sum(r['total_pence'] for r in many(db,"SELECT total_pence,received_date FROM job_materials WHERE archived=0 AND status='received'") if inside(r['received_date']))
    work=queue(db);ready=[r for r in work if r['eligible'] and r['effective_state'] in ('open','prepared')]
    return {'period':{'start':start,'end':end,'timezone':'Europe/London','inclusive':True},'as_of':current,
      'period_counts':{'customers_created':sum(inside(local_day(c['created_at'])) for c in customers),'jobs_created':sum(inside(local_day(j['created_at'])) for j in jobs),'completed_jobs':sum(j['status']=='completed' and inside(j['workflow']['completed_date']) for j in jobs),'quote_revisions_created':sum(inside(local_day(q['created_at'])) for q in quotes)},
      'period_money':{'issued_invoice_value_pence':sum(i['total_pence'] for i in issued if inside(local_day(i['issued_at']))),'recorded_receipts_pence':sum(p['amount_pence'] for p in receipts if inside(p['paid_on'])),'internal_labour_cost_pence':labour,'received_material_cost_pence':materials},
      'current':{'open_jobs':sum(open_job(j['status'],j['workflow']['archived']) for j in jobs),'ready_reviews':len(ready),'due_next_actions':sum(r['kind']=='next_action' for r in ready),'open_quote_estimate_pence':sum(q['total_pence'] for q in estimate),'issued_invoice_balance_pence':sum(i['balance_pence'] for i in issued)},
      'definitions':{'period_counts':'Created timestamps use UK local dates. Completed jobs use explicitly saved completion dates and current completed status. Quote counts include every revision, not distinct jobs. Archived historical records remain included. Older completions without a saved completion date are excluded.',
      'issued_invoice_value_pence':'Currently issued, non-void invoices whose actual issue timestamp falls in the selected UK period. Gross saved invoice amounts; stage/deposit requests add nothing. This is not recognised revenue or a historical accounting statement.',
      'recorded_receipts_pence':'Existing receipt ledger using paid-on dates, excluding reversed recording errors. Corrections retain their ledger treatment; these are manually recorded payments, not bank-cleared evidence.',
      'internal_costs':'Active saved labour entries by work date and received materials by received date. Includes only converted/recorded costs, excludes archived entries and costs with no relevant date. Does not calculate accounting profit, overheads, VAT recovery or tax.',
      'current':'Current-state snapshot, independent of the selected period. Open quote estimate includes current unexpired draft/shared quotes for open, unarchived jobs. It is potential work, not invoiced value. Ready reviews includes prepared local drafts; delivery is unconfirmed. Next actions to review includes undated actions or actions dated today or earlier, but excludes snoozed, dismissed and completed reviews. Saved job action text and dates stay unchanged until the owner edits them.'}}

def mount_report(app,store,session):
    @app.get('/api/reports/operations')
    def operations(request:Request,start:str=Query(...),end:str=Query(...)):
        s=session(request)
        with store.tenant(s['business_id']) as db:return report(db,start,end)
