"""One-off seed: registers translation_keys English source_text and hi/mr/hinglish
translation_values for the "security-vapt" PageInfoButton content.

Usage: docker compose exec api python seed_translations_pageinfo_security_vapt.py
"""
import asyncio
import uuid
from datetime import datetime, timezone

from sqlalchemy import text
from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker, create_async_engine

from ams.core.config import settings

NAMESPACE = "help"

# key -> (english, hi, mr, hinglish)
SECURITY_VAPT = {
    "security-vapt.title": (
        "Security & VAPT Governance",
        "सुरक्षा और VAPT गवर्नेंस",
        "सुरक्षा आणि VAPT गव्हर्नन्स",
        "Security & VAPT Governance",
    ),
    "security-vapt.subtitle": (
        "Vulnerability findings, scans, compliance assessments, security controls, and login/session events",
        "Vulnerability findings, scans, compliance assessments, security controls, और login/session events",
        "Vulnerability findings, scans, compliance assessments, security controls, आणि login/session events",
        "Vulnerability findings, scans, compliance assessments, security controls, aur login/session events",
    ),
    "security-vapt.body.0": (
        "Central register for security posture: findings raised from scans (SAST/DAST/manual/pentest), the scans themselves, framework assessments (ISO 27001, STQC, OWASP, DPDP), configurable security controls (MFA, IP allowlists, etc.), and the raw login/session event log.",
        "सुरक्षा स्थिति (security posture) के लिए केंद्रीय register: scans (SAST/DAST/manual/pentest) से उठाए गए findings, स्वयं scans, framework assessments (ISO 27001, STQC, OWASP, DPDP), configurable security controls (MFA, IP allowlists, आदि), और कच्चा login/session event log।",
        "सुरक्षा स्थिती (security posture) साठी केंद्रीय register: scans (SAST/DAST/manual/pentest) मधून उपस्थित झालेले findings, स्वतः scans, framework assessments (ISO 27001, STQC, OWASP, DPDP), configurable security controls (MFA, IP allowlists, इ.), आणि कच्चा login/session event log.",
        "Security posture ke liye central register: scans (SAST/DAST/manual/pentest) se raise hue findings, scans khud, framework assessments (ISO 27001, STQC, OWASP, DPDP), configurable security controls (MFA, IP allowlists, etc.), aur raw login/session event log.",
    ),
    "security-vapt.body.1": (
        "The dashboard's risk score is computed as critical×10 + high×5 + medium×2 + low×1 across all open findings.",
        "Dashboard का risk score सभी open findings में critical×10 + high×5 + medium×2 + low×1 के रूप में calculate होता है।",
        "Dashboard चा risk score सर्व open findings मध्ये critical×10 + high×5 + medium×2 + low×1 असा calculate होतो.",
        "Dashboard ka risk score sabhi open findings mein critical×10 + high×5 + medium×2 + low×1 ke roop mein calculate hota hai.",
    ),
    "security-vapt.stepsHeading": (
        "Finding lifecycle",
        "निष्कर्ष जीवनचक्र",
        "निष्कर्षाचे जीवनचक्र",
        "Finding ka lifecycle",
    ),
    "security-vapt.steps.0.label": ("Discovery", "खोज", "शोध", "Discovery"),
    "security-vapt.steps.0.caption": (
        "Created when a scan's results are imported.",
        "यह तब बनता है जब किसी scan के results import किए जाते हैं।",
        "जेव्हा एखाद्या scan चे results import केले जातात तेव्हा हे तयार होते.",
        "Ye tab create hota hai jab kisi scan ke results import kiye jaate hain.",
    ),
    "security-vapt.steps.1.label": ("Assessment", "आकलन", "मूल्यांकन", "Assessment"),
    "security-vapt.steps.1.caption": (
        "Triaged; owner reviews severity and impact.",
        "Triage किया जाता है; owner severity और impact की समीक्षा करता है।",
        "Triage केले जाते; owner severity आणि impact चा आढावा घेतो.",
        "Triage hota hai; owner severity aur impact review karta hai.",
    ),
    "security-vapt.steps.2.label": ("Remediation", "निवारण", "निवारण", "Remediation"),
    "security-vapt.steps.2.caption": (
        'Assigned to a user; fix in progress ("To Remediation").',
        'किसी user को assign किया जाता है; fix प्रगति में होता है ("To Remediation")।',
        'एखाद्या user ला assign केले जाते; fix प्रगतीत असतो ("To Remediation").',
        'Kisi user ko assign hota hai; fix in progress hota hai ("To Remediation").',
    ),
    "security-vapt.steps.3.label": ("Retest", "पुनः परीक्षण", "पुनर्चाचणी", "Retest"),
    "security-vapt.steps.3.caption": (
        "Fix verified against the original finding.",
        "Fix को original finding के विरुद्ध verify किया जाता है।",
        "Fix मूळ finding च्या विरुद्ध verify केला जातो.",
        "Fix ko original finding ke against verify kiya jaata hai.",
    ),
    "security-vapt.steps.4.label": ("Closed", "बंद", "बंद", "Closed"),
    "security-vapt.steps.4.caption": (
        "Retest passed; finding is resolved.",
        "Retest pass हो जाता है; finding resolve हो जाती है।",
        "Retest pass होतो; finding resolve होते.",
        "Retest pass ho jaata hai; finding resolve ho jaati hai.",
    ),
    "security-vapt.fieldRules.0.name": ("Severity", "गंभीरता", "तीव्रता", "Severity"),
    "security-vapt.fieldRules.0.description": (
        "critical / high / medium / low / info — drives the risk score and dashboard grouping.",
        "critical / high / medium / low / info — यह risk score और dashboard grouping को नियंत्रित करता है।",
        "critical / high / medium / low / info — हे risk score आणि dashboard grouping नियंत्रित करते.",
        "critical / high / medium / low / info — ye risk score aur dashboard grouping ko drive karta hai.",
    ),
    "security-vapt.fieldRules.1.name": ("Status", "स्थिति", "स्थिती", "Status"),
    "security-vapt.fieldRules.1.description": (
        "discovery, assessment, remediation, retest, closed, or accepted; only assessment→remediation, remediation→retest, and retest→closed are exposed as buttons.",
        "discovery, assessment, remediation, retest, closed, या accepted; केवल assessment→remediation, remediation→retest, और retest→closed ही buttons के रूप में उपलब्ध हैं।",
        "discovery, assessment, remediation, retest, closed, किंवा accepted; फक्त assessment→remediation, remediation→retest, आणि retest→closed हेच buttons म्हणून उपलब्ध आहेत.",
        "discovery, assessment, remediation, retest, closed, ya accepted; sirf assessment→remediation, remediation→retest, aur retest→closed hi buttons ke roop mein expose kiye gaye hain.",
    ),
    "security-vapt.fieldRules.2.name": ("Assigned To", "सौंपा गया व्यक्ति", "नेमलेली व्यक्ती", "Assigned To"),
    "security-vapt.fieldRules.2.description": (
        "User responsible for remediating the finding; set via the Assign action.",
        "finding को ठीक करने के लिए ज़िम्मेदार user; Assign action के ज़रिए सेट किया जाता है।",
        "finding दुरुस्त करण्यासाठी जबाबदार user; Assign action द्वारे सेट केला जातो.",
        "Finding ko fix karne ke liye responsible user; Assign action se set hota hai.",
    ),
    "security-vapt.fieldRules.3.name": ("Affected Component", "प्रभावित घटक", "प्रभावित घटक", "Affected Component"),
    "security-vapt.fieldRules.3.description": (
        "Free-text identifier of the impacted system/module for triage context.",
        "Triage context के लिए प्रभावित system/module का free-text identifier।",
        "Triage context साठी प्रभावित system/module चा free-text identifier.",
        "Triage context ke liye impacted system/module ka free-text identifier.",
    ),
    "security-vapt.fieldRules.4.name": ("Scan Import JSON", "स्कैन इम्पोर्ट JSON", "स्कॅन इम्पोर्ट JSON", "Scan Import JSON"),
    "security-vapt.fieldRules.4.description": (
        "Array of findings with title required per item; severity/description/cwe_id/owasp_category/affected_component optional.",
        "Findings का array, जिसमें प्रत्येक item के लिए title आवश्यक है; severity/description/cwe_id/owasp_category/affected_component वैकल्पिक हैं।",
        "Findings चा array, ज्यामध्ये प्रत्येक item साठी title आवश्यक आहे; severity/description/cwe_id/owasp_category/affected_component ऐच्छिक आहेत.",
        "Findings ka array, jisme har item ke liye title required hai; severity/description/cwe_id/owasp_category/affected_component optional hain.",
    ),
    "security-vapt.tip.title": (
        'New findings never start past "discovery"',
        'नए findings कभी भी "discovery" से आगे शुरू नहीं होते',
        'नवीन findings कधीही "discovery" च्या पुढे सुरू होत नाहीत',
        'Naye findings kabhi bhi "discovery" se aage start nahi hote',
    ),
    "security-vapt.tip.body": (
        "There's no UI or API path to move a finding straight from discovery to assessment/accepted — it only advances once you import scan results, and the exposed buttons only cover assessment→remediation→retest→closed. If a finding looks stuck at discovery, it hasn't been triaged yet, not that the page is broken.",
        "किसी finding को discovery से सीधे assessment/accepted पर ले जाने का कोई UI या API path नहीं है — यह तभी आगे बढ़ता है जब आप scan results import करते हैं, और exposed buttons केवल assessment→remediation→retest→closed को cover करते हैं। यदि कोई finding discovery पर अटका दिखे, तो इसका मतलब है कि उसे अभी triage नहीं किया गया है, यह नहीं कि page खराब है।",
        "एखादी finding discovery मधून थेट assessment/accepted वर नेण्यासाठी कोणताही UI किंवा API path नाही — ती फक्त तेव्हाच पुढे जाते जेव्हा तुम्ही scan results import करता, आणि exposed buttons फक्त assessment→remediation→retest→closed कव्हर करतात. जर एखादी finding discovery वर अडकलेली दिसत असेल, तर याचा अर्थ ती अजून triage झालेली नाही, page बिघडलेले नाही.",
        "Kisi finding ko discovery se seedha assessment/accepted par le jaane ka koi UI ya API path nahi hai — ye tabhi aage badhta hai jab aap scan results import karte hain, aur exposed buttons sirf assessment→remediation→retest→closed cover karte hain. Agar koi finding discovery par stuck dikhe, to iska matlab hai ki wo abhi tak triage nahi hui hai, ye nahi ki page kharab hai.",
    ),
}


async def seed_for_session(session: AsyncSession) -> tuple[int, int]:
    now = datetime.now(timezone.utc)
    keys_upserted = 0
    values_upserted = 0
    for key, (en, hi, mr, hinglish) in SECURITY_VAPT.items():
        key_id = (await session.execute(
            text("SELECT id FROM translation_keys WHERE namespace = :ns AND key = :key"),
            {"ns": NAMESPACE, "key": key},
        )).scalar_one_or_none()
        if key_id:
            await session.execute(
                text("UPDATE translation_keys SET source_text = :src WHERE id = :id"),
                {"src": en, "id": key_id},
            )
        else:
            key_id = str(uuid.uuid4())
            await session.execute(
                text("""INSERT INTO translation_keys (id, namespace, key, source_text, created_at)
                        VALUES (:id, :ns, :key, :src, :now)"""),
                {"id": key_id, "ns": NAMESPACE, "key": key, "src": en, "now": now},
            )
            keys_upserted += 1

        for lang_code, value in (("hi", hi), ("mr", mr), ("hinglish", hinglish)):
            existing = (await session.execute(
                text("SELECT id FROM translation_values WHERE key_id = :kid AND language_code = :lc"),
                {"kid": key_id, "lc": lang_code},
            )).scalar_one_or_none()
            if existing:
                await session.execute(
                    text("UPDATE translation_values SET value = :val, updated_at = :now WHERE id = :id"),
                    {"val": value, "now": now, "id": existing},
                )
            else:
                await session.execute(
                    text("""INSERT INTO translation_values (id, key_id, language_code, value, updated_by, updated_at)
                            VALUES (:id, :kid, :lc, :val, NULL, :now)"""),
                    {"id": str(uuid.uuid4()), "kid": key_id, "lc": lang_code, "val": value, "now": now},
                )
                values_upserted += 1
    await session.commit()
    return keys_upserted, values_upserted


async def main() -> None:
    engine = create_async_engine(settings.DATABASE_URL, echo=False)
    Session = async_sessionmaker(engine, class_=AsyncSession, expire_on_commit=False)

    async with Session() as session:
        tenants = (await session.execute(
            text("SELECT id::text AS id, slug FROM public.tenants WHERE status != 'archived'")
        )).fetchall()

    for tenant in tenants:
        schema = f"tenant_{tenant.id.replace('-', '_')}"
        async with Session() as session:
            await session.execute(text(f"SET search_path TO {schema}, public"))
            try:
                k, v = await seed_for_session(session)
                print(f"  seeded {k} new keys, {v} new values: {tenant.slug}")
            except Exception as exc:
                print(f"  SKIPPED {tenant.slug}: {exc}")
                await session.rollback()

    await engine.dispose()
    print(f"Done — {len(tenants)} tenant(s) processed, {len(SECURITY_VAPT)} security-vapt keys.")


if __name__ == "__main__":
    asyncio.run(main())
