"""Explicit customer reuse/history. No fuzzy matching or automatic merging."""
import json
from fastapi import HTTPException, Query, Request
from pydantic import Field, StrictBool, field_validator
from .models import Strict, Enquiry
from .material_rules import Identity, VersionNumber
from .store import one, uid, now, audit

SCHEMA = '''
CREATE TABLE IF NOT EXISTS customer_changes(id INTEGER PRIMARY KEY AUTOINCREMENT,
 customer_id TEXT NOT NULL REFERENCES customers(id), before_value TEXT NOT NULL,
 after_value TEXT NOT NULL, actor TEXT NOT NULL, created_at TEXT NOT NULL);
CREATE TABLE IF NOT EXISTS customer_links(id INTEGER PRIMARY KEY AUTOINCREMENT,
 job_id TEXT NOT NULL REFERENCES jobs(id), from_customer_id TEXT NOT NULL REFERENCES customers(id),
 to_customer_id TEXT NOT NULL REFERENCES customers(id), actor TEXT NOT NULL, created_at TEXT NOT NULL);
'''
FIELDS = 'id,name,email,phone,address,version,created_at,portal_version,CASE WHEN portal_hash IS NULL THEN 0 ELSE 1 END AS portal_enabled'


def setup(db):
    if 'version' not in {r['name'] for r in db.execute('PRAGMA table_info(customers)')}:
        db.execute('ALTER TABLE customers ADD COLUMN version INTEGER NOT NULL DEFAULT 1')
    db.executescript(SCHEMA)


def required(row):
    if not row:
        raise HTTPException(404, 'Record not found in this business.')
    return row


class Contact(Strict):
    name: str = Field(min_length=2, max_length=100)
    email: str = Field(default='', max_length=180)
    phone: str = Field(default='', max_length=40)
    address: str = Field(default='', max_length=250)

    @field_validator('email')
    @classmethod
    def valid_email(cls, value):
        return Enquiry.email_shape(value)


class ContactEdit(Contact):
    version: VersionNumber


class NewWork(Strict):
    customer_version: VersionNumber
    service: str = Field(min_length=2, max_length=120)
    message: str = Field(min_length=5, max_length=3000)


class LinkReview(Strict):
    customer_id: Identity
    customer_version: VersionNumber
    job_version: VersionNumber


class LinkConfirm(LinkReview):
    confirmed: StrictBool

    @field_validator('confirmed')
    @classmethod
    def confirmed_true(cls, value):
        if not value:
            raise ValueError('Review and confirm the customer link.')
        return value


def mount_customers(app, store, session, once):
    @app.get('/api/customers')
    def search(request: Request, q: str = Query(default='', max_length=180), state: str = Query('active',pattern='^(active|archived|merged|all)$')):
        from .customer_review import directory
        s = session(request)
        with store.tenant(s['business_id']) as db:return directory(db,q,state)

    @app.post('/api/customers')
    def create(payload: Contact, request: Request):
        s = session(request, csrf=True)
        with store.tenant(s['business_id']) as db:
            def action():
                cid = uid()
                db.execute('INSERT INTO customers(id,name,email,phone,address,created_at) VALUES(?,?,?,?,?,?)', (cid,payload.name,payload.email,payload.phone,payload.address,now()))
                from .customer_review import register
                register(db,cid)
                audit(db,'customer.created',cid)
                return one(db,'SELECT '+FIELDS+' FROM customers WHERE id=?',(cid,))
            return once(db,request,payload.model_dump(),action)

    @app.put('/api/customers/{customer_id}')
    def edit(customer_id: str, payload: ContactEdit, request: Request):
        s = session(request, csrf=True)
        with store.tenant(s['business_id']) as db:
            def action():
                from .customer_review import active,record
                active(db,customer_id)
                before = required(one(db,'SELECT '+FIELDS+' FROM customers WHERE id=?',(customer_id,)))
                if before['version'] != payload.version:
                    raise HTTPException(409, 'This customer changed. Refresh before saving.')
                if all(before[k] == getattr(payload,k) for k in ('name','email','phone','address')):
                    return before
                # Identity/contact corrections revoke passwords, tokens and sessions.
                from .portal_access import revoke
                revoke(db,customer_id,s['subject'])
                from .feedback import invalidate
                invalidate(db,customer_id=customer_id,actor=s['subject'],detail='Customer contact changed; prepare a new exact-record request.')
                db.execute('UPDATE customers SET name=?,email=?,phone=?,address=?,version=version+1,portal_hash=NULL WHERE id=?', (payload.name,payload.email,payload.phone,payload.address,customer_id))
                after = one(db,'SELECT '+FIELDS+' FROM customers WHERE id=?',(customer_id,))
                db.execute('INSERT INTO customer_changes(customer_id,before_value,after_value,actor,created_at) VALUES(?,?,?,?,?)',(customer_id,json.dumps(before),json.dumps(after),s['subject'],now()))
                record(db,customer_id,'contact',s['subject'],'Contact corrected; portal and feedback permission revoked.',advance=True)
                audit(db,'customer.contact_updated_portal_revoked',customer_id)
                return after
            return once(db,request,payload.model_dump(),action)

    @app.post('/api/customers/{customer_id}/jobs')
    def new_work(customer_id: str, payload: NewWork, request: Request):
        s = session(request, csrf=True)
        with store.tenant(s['business_id']) as db:
            def action():
                from .customer_review import active
                c = active(db,customer_id)
                if c['version'] != payload.customer_version:
                    raise HTTPException(409,'Customer details changed. Refresh and select the customer again.')
                jid = uid()
                db.execute('INSERT INTO jobs(id,customer_id,service,message,status,source,created_at) VALUES(?,?,?,?,?,?,?)', (jid,customer_id,payload.service,payload.message,'new','existing_customer',now()))
                audit(db,'job.created_for_existing_customer',jid)
                from .workflow import register_job
                register_job(db,jid)
                return {'id':jid,'customer_id':customer_id}
            return once(db,request,payload.model_dump(),action)

    @app.get('/api/customers/{customer_id}/history')
    def history(customer_id: str, request: Request):
        from .customer_history import history as saved_history
        s = session(request)
        with store.tenant(s['business_id']) as db:
            db.execute('BEGIN')
            return saved_history(db,customer_id)

    @app.post('/api/jobs/{job_id}/customer-link-preview')
    def preview(job_id: str, payload: LinkReview, request: Request):
        session(request,csrf=True)
        raise HTTPException(410,'Use Customers → Review record transfer for an exact versioned preview and reason.')

    @app.post('/api/jobs/{job_id}/customer-link')
    def link(job_id: str, payload: LinkConfirm, request: Request):
        session(request,csrf=True)
        raise HTTPException(410,'Use Customers → Review record transfer. The former bare-enquiry write is retired.')
