"""Feedback-only credentials and explicit customer-authored public permission."""
from typing import Literal
from pydantic import Field, StrictBool, ConfigDict, model_validator, field_validator
from .models import Strict
from .material_rules import Identity, VersionNumber

CONSENT_WORDING='I allow this business to display the exact public name and statement below as a selected testimonial on its website. My rating is included only if I choose it. My private feedback stays private. I can withdraw permission; copies already downloaded cannot be recalled.'
CONSENT_VERSION=1
SCHEMA='''
CREATE TABLE IF NOT EXISTS feedback_requests(id TEXT PRIMARY KEY, job_id TEXT NOT NULL REFERENCES jobs(id), customer_id TEXT NOT NULL REFERENCES customers(id), customer_version INTEGER NOT NULL, job_version INTEGER NOT NULL, delivery_email TEXT NOT NULL, service TEXT NOT NULL, reason TEXT NOT NULL, state TEXT NOT NULL CHECK(state IN ('pending','responded','revoked','archived')), version INTEGER NOT NULL, access_version INTEGER NOT NULL, expires REAL NOT NULL, prepared_by TEXT NOT NULL, created_at TEXT NOT NULL);
CREATE INDEX IF NOT EXISTS feedback_job ON feedback_requests(job_id);
CREATE TABLE IF NOT EXISTS feedback_tokens(id TEXT PRIMARY KEY, request_id TEXT NOT NULL REFERENCES feedback_requests(id), token_hash TEXT UNIQUE NOT NULL, access_version INTEGER NOT NULL, expires REAL NOT NULL, created_at TEXT NOT NULL);
CREATE TABLE IF NOT EXISTS feedback_responses(request_id TEXT PRIMARY KEY REFERENCES feedback_requests(id), answers TEXT NOT NULL, actor TEXT NOT NULL, submitted_version INTEGER NOT NULL, created_at TEXT NOT NULL);
CREATE TABLE IF NOT EXISTS feedback_consents(request_id TEXT PRIMARY KEY REFERENCES feedback_requests(id), state TEXT NOT NULL CHECK(state IN ('private','approved','withdrawn','suspended')), display_name TEXT NOT NULL, statement TEXT NOT NULL, share_rating INTEGER NOT NULL CHECK(share_rating IN (0,1)), version INTEGER NOT NULL, wording_version INTEGER NOT NULL, created_at TEXT NOT NULL);
CREATE TABLE IF NOT EXISTS feedback_publications(request_id TEXT PRIMARY KEY REFERENCES feedback_requests(id), consent_version INTEGER NOT NULL, projection TEXT NOT NULL, state TEXT NOT NULL CHECK(state IN ('published','hidden')), published_at TEXT NOT NULL);
CREATE TABLE IF NOT EXISTS feedback_history(id INTEGER PRIMARY KEY AUTOINCREMENT, request_id TEXT NOT NULL REFERENCES feedback_requests(id), version INTEGER NOT NULL, action TEXT NOT NULL, actor TEXT NOT NULL, snapshot TEXT NOT NULL, detail TEXT NOT NULL, created_at TEXT NOT NULL, UNIQUE(request_id,version));
'''

class Consent(Strict):
    model_config=ConfigDict(extra='forbid',str_strip_whitespace=False)
    allow_public: StrictBool=False
    display_name: str=Field(default='',max_length=100)
    statement: str=Field(default='',max_length=2000)
    share_rating: StrictBool=False
    wording_version: int=Field(default=1,strict=True,ge=1,le=1)

    @field_validator('display_name','statement')
    @classmethod
    def text(cls,value):
        if any(ord(ch)<32 and ch not in '\n\t' for ch in value):raise ValueError('Use plain text without control characters.')
        return value

    @model_validator(mode='after')
    def permission(self):
        if self.allow_public and (not self.display_name.strip() or not self.statement.strip()):raise ValueError('Choose your exact public name and statement.')
        if not self.allow_public and (self.display_name or self.statement or self.share_rating):raise ValueError('Private feedback must not include a public projection.')
        return self

class Answers(Strict):
    model_config=ConfigDict(extra='forbid',str_strip_whitespace=False)
    overall_rating: int=Field(strict=True,ge=1,le=5)
    quality_rating: int=Field(strict=True,ge=1,le=5)
    communication_rating: int=Field(strict=True,ge=1,le=5)
    timeliness_rating: int=Field(strict=True,ge=1,le=5)
    recommend: StrictBool
    comments: str=Field(default='',max_length=4000)
    improvement_suggestions: str=Field(default='',max_length=4000)
    _text=field_validator('comments','improvement_suggestions')(Consent.text.__func__)

class Submission(Strict):
    version: VersionNumber
    answers: Answers
    consent: Consent=Field(default_factory=Consent)
    confirmed: StrictBool

    @field_validator('confirmed')
    @classmethod
    def confirmation(cls,value):
        if not value:raise ValueError('Review and confirm this choice.')
        return value

class Permission(Strict):
    version: VersionNumber
    consent: Consent
    confirmed: StrictBool

    @field_validator('confirmed')
    @classmethod
    def confirmation(cls,value):
        if not value:raise ValueError('Review and confirm this choice.')
        return value

class Code(Strict):
    code: str=Field(min_length=32,max_length=100)

class TokenSubmission(Submission,Code):pass
class TokenPermission(Permission,Code):pass

class Prepare(Strict):
    job_id: Identity
    customer_id: Identity
    job_version: VersionNumber
    customer_version: VersionNumber
    expires_days: int=Field(default=14,strict=True,ge=1,le=30)
    reason: str=Field(default='',max_length=500)

class Action(Strict):
    version: VersionNumber
    reason: str=Field(min_length=5,max_length=500)

class Reissue(Action):
    expires_days: int=Field(default=14,strict=True,ge=1,le=30)

class Publish(Strict):
    version: VersionNumber
    projection_hash: str=Field(pattern=r'^[a-f0-9]{64}$')
    confirmed: StrictBool

    @field_validator('confirmed')
    @classmethod
    def confirmation(cls,value):
        if not value:raise ValueError('Review and confirm this choice.')
        return value

TABLES=('feedback_history','feedback_tokens','feedback_publications','feedback_consents','feedback_responses','feedback_requests')
