"""
Seed script — run once to populate initial data.
Usage: python -m app.utils.seed
"""

import asyncio
from datetime import date
from decimal import Decimal

from sqlalchemy import select

from app.core.config import settings
from app.core.database import AsyncSessionLocal
from app.core.security import hash_password
from app.models.product import JenisProdukEnum, Produk, ProdukHarga
from app.models.role import AksiEnum, ModulEnum, Role, RolePermission
from app.models.user import User


# Permission matrix for default roles
SPBU_ADMIN_PERMISSIONS = [
    (ModulEnum.dashboard, AksiEnum.view),
    (ModulEnum.penjualan, AksiEnum.view),
    (ModulEnum.penjualan, AksiEnum.create),
    (ModulEnum.penjualan, AksiEnum.edit),
    (ModulEnum.penjualan, AksiEnum.approve),
    (ModulEnum.penjualan, AksiEnum.export),
    (ModulEnum.stock, AksiEnum.view),
    (ModulEnum.stock, AksiEnum.create),
    (ModulEnum.stock, AksiEnum.edit),
    (ModulEnum.penebusan, AksiEnum.view),
    (ModulEnum.penebusan, AksiEnum.create),
    (ModulEnum.penebusan, AksiEnum.edit),
    (ModulEnum.penerimaan, AksiEnum.view),
    (ModulEnum.penerimaan, AksiEnum.create),
    (ModulEnum.penerimaan, AksiEnum.edit),
    (ModulEnum.expenses, AksiEnum.view),
    (ModulEnum.expenses, AksiEnum.create),
    (ModulEnum.expenses, AksiEnum.edit),
    (ModulEnum.penyetoran, AksiEnum.view),
    (ModulEnum.penyetoran, AksiEnum.create),
    (ModulEnum.penyetoran, AksiEnum.approve),
    (ModulEnum.rekonsiliasi, AksiEnum.view),
    (ModulEnum.rekonsiliasi, AksiEnum.approve),
    (ModulEnum.laporan, AksiEnum.view),
    (ModulEnum.laporan, AksiEnum.export),
    (ModulEnum.analytics, AksiEnum.view),
    (ModulEnum.anomali, AksiEnum.view),
    (ModulEnum.anomali, AksiEnum.edit),
    (ModulEnum.products, AksiEnum.view),
    (ModulEnum.tangki, AksiEnum.view),
    (ModulEnum.tangki, AksiEnum.create),
    (ModulEnum.tangki, AksiEnum.edit),
    (ModulEnum.spbu_settings, AksiEnum.view),
    (ModulEnum.spbu_settings, AksiEnum.edit),
    (ModulEnum.contracts, AksiEnum.view),
    (ModulEnum.contracts, AksiEnum.create),
    (ModulEnum.contracts, AksiEnum.edit),
    (ModulEnum.users, AksiEnum.view),
    (ModulEnum.users, AksiEnum.create),
    (ModulEnum.users, AksiEnum.edit),
    (ModulEnum.operators, AksiEnum.view),
    (ModulEnum.jadwal, AksiEnum.view),
    (ModulEnum.jadwal, AksiEnum.create),
    (ModulEnum.jadwal, AksiEnum.edit),
    (ModulEnum.jadwal, AksiEnum.delete),
    (ModulEnum.absensi, AksiEnum.view),
    (ModulEnum.absensi, AksiEnum.create),
    (ModulEnum.absensi, AksiEnum.approve),
]

MANAGER_PERMISSIONS = [
    (ModulEnum.dashboard, AksiEnum.view),
    (ModulEnum.penjualan, AksiEnum.view),
    (ModulEnum.penjualan, AksiEnum.export),
    (ModulEnum.stock, AksiEnum.view),
    (ModulEnum.penebusan, AksiEnum.view),
    (ModulEnum.penerimaan, AksiEnum.view),
    (ModulEnum.expenses, AksiEnum.view),
    (ModulEnum.penyetoran, AksiEnum.view),
    (ModulEnum.rekonsiliasi, AksiEnum.view),
    (ModulEnum.laporan, AksiEnum.view),
    (ModulEnum.laporan, AksiEnum.export),
    (ModulEnum.analytics, AksiEnum.view),
    (ModulEnum.anomali, AksiEnum.view),
    (ModulEnum.products, AksiEnum.view),
    (ModulEnum.tangki, AksiEnum.view),
    (ModulEnum.contracts, AksiEnum.view),
    (ModulEnum.users, AksiEnum.view),
    (ModulEnum.operators, AksiEnum.view),
    (ModulEnum.jadwal, AksiEnum.view),
    (ModulEnum.absensi, AksiEnum.view),
    (ModulEnum.absensi, AksiEnum.approve),
]

OPERATOR_PERMISSIONS = [
    (ModulEnum.dashboard, AksiEnum.view),
    (ModulEnum.penjualan, AksiEnum.view),
    (ModulEnum.penjualan, AksiEnum.create),
    (ModulEnum.stock, AksiEnum.view),
    (ModulEnum.stock, AksiEnum.create),
    (ModulEnum.expenses, AksiEnum.view),
    (ModulEnum.expenses, AksiEnum.create),
    (ModulEnum.penyetoran, AksiEnum.view),
    (ModulEnum.penyetoran, AksiEnum.create),
    (ModulEnum.operators, AksiEnum.view),
    (ModulEnum.jadwal, AksiEnum.view),
    (ModulEnum.absensi, AksiEnum.view),
    (ModulEnum.absensi, AksiEnum.create),
]

VIEWER_PERMISSIONS = [
    (ModulEnum.dashboard, AksiEnum.view),
    (ModulEnum.penjualan, AksiEnum.view),
    (ModulEnum.stock, AksiEnum.view),
    (ModulEnum.penebusan, AksiEnum.view),
    (ModulEnum.penerimaan, AksiEnum.view),
    (ModulEnum.expenses, AksiEnum.view),
    (ModulEnum.penyetoran, AksiEnum.view),
    (ModulEnum.rekonsiliasi, AksiEnum.view),
    (ModulEnum.laporan, AksiEnum.view),
    (ModulEnum.analytics, AksiEnum.view),
    (ModulEnum.products, AksiEnum.view),
    (ModulEnum.tangki, AksiEnum.view),
    (ModulEnum.contracts, AksiEnum.view),
    (ModulEnum.operators, AksiEnum.view),
    (ModulEnum.jadwal, AksiEnum.view),
    (ModulEnum.absensi, AksiEnum.view),
]

PRODUCTS_SEED = [
    {
        "nama": "Pertalite",
        "kode": "RON90",
        "jenis": JenisProdukEnum.gasoline,
        "is_subsidi": True,
        "kuota_config": {
            "roda_4_pribadi": 50,
            "roda_6_plus": 200,
        },
        "harga": Decimal("10000.000"),
    },
    {
        "nama": "Pertamax",
        "kode": "RON92",
        "jenis": JenisProdukEnum.gasoline,
        "is_subsidi": False,
        "harga": Decimal("13900.000"),
    },
    {
        "nama": "Pertamax Turbo",
        "kode": "RON98",
        "jenis": JenisProdukEnum.gasoline,
        "is_subsidi": False,
        "harga": Decimal("15900.000"),
    },
    {
        "nama": "Biosolar",
        "kode": "CN48",
        "jenis": JenisProdukEnum.diesel,
        "is_subsidi": True,
        "kuota_config": {
            "roda_4_pribadi": 50,
            "angkutan_umum": 80,
            "roda_6_plus": 200,
        },
        "harga": Decimal("6800.000"),
    },
    {
        "nama": "Dexlite",
        "kode": "CN51",
        "jenis": JenisProdukEnum.diesel,
        "is_subsidi": False,
        "harga": Decimal("15350.000"),
    },
    {
        "nama": "Pertadex",
        "kode": "CN53",
        "jenis": JenisProdukEnum.diesel,
        "is_subsidi": False,
        "harga": Decimal("16200.000"),
    },
]


async def seed() -> None:
    async with AsyncSessionLocal() as db:
        # Super admin
        existing = await db.execute(
            select(User).where(User.email == settings.SUPERADMIN_EMAIL)
        )
        if not existing.scalar_one_or_none():
            admin = User(
                name=settings.SUPERADMIN_NAME,
                email=settings.SUPERADMIN_EMAIL,
                password_hash=hash_password(settings.SUPERADMIN_PASSWORD),
                is_superadmin=True,
                is_active=True,
            )
            db.add(admin)
            print(f"✓ Superadmin created: {settings.SUPERADMIN_EMAIL}")
        else:
            print(f"  Superadmin already exists: {settings.SUPERADMIN_EMAIL}")

        # System roles
        default_roles = [
            ("SPBU Admin", "Akses penuh semua modul kecuali spbu_management", SPBU_ADMIN_PERMISSIONS),
            ("Manager", "View + export semua modul", MANAGER_PERMISSIONS),
            ("Operator", "Input laporan harian", OPERATOR_PERMISSIONS),
            ("Viewer", "View-only semua modul", VIEWER_PERMISSIONS),
        ]
        for nama, deskripsi, perms in default_roles:
            existing_role = await db.execute(
                select(Role).where(Role.nama == nama, Role.spbu_id.is_(None))
            )
            role = existing_role.scalar_one_or_none()
            if not role:
                role = Role(
                    nama=nama,
                    deskripsi=deskripsi,
                    spbu_id=None,
                    is_system=True,
                )
                db.add(role)
                await db.flush()
                for modul, aksi in perms:
                    db.add(RolePermission(role_id=role.id, modul=modul, aksi=aksi))
                print(f"✓ Role created: {nama}")
            else:
                print(f"  Role already exists: {nama}")
            if role.nama == "Operator":
                role.can_be_scheduled = True
                role.can_login_web = False

        # Products
        today = date.today()
        for p in PRODUCTS_SEED:
            harga = p.pop("harga")
            existing_produk = await db.execute(
                select(Produk).where(Produk.kode == p["kode"])
            )
            produk = existing_produk.scalar_one_or_none()
            if not produk:
                produk = Produk(**p)
                db.add(produk)
                await db.flush()
                db.add(ProdukHarga(produk_id=produk.id, harga=harga, berlaku_mulai=today))
                print(f"✓ Product created: {p['nama']}")
            else:
                p["harga"] = harga  # restore for next iteration
                print(f"  Product already exists: {p['nama']}")

        await db.commit()
        print("\n✅ Seeding complete!")


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