"""Seed OpenStack identity and sample cloud resources."""

from __future__ import annotations

from asyncpg import Connection

from app.openstack.ids import oid
from app.security.auth import hash_secret


async def seed_openstack(conn: Connection, *, password: str = "secret") -> dict[str, object]:
    """Idempotent OpenStack lab seed (admin + demo project/user + sample resources)."""

    domain_id = oid("domain:Default")
    admin_project = oid("project:admin")
    demo_project = oid("project:demo")
    admin_user = oid("user:admin")
    demo_user = oid("user:demo")
    role_admin = oid("role:admin")
    role_member = oid("role:member")
    pw = hash_secret(password, salt=b"openstack-sim-v1")

    await conn.execute(
        """INSERT INTO os_domains(id, name, description, enabled)
           VALUES($1, 'Default', 'Default domain', true)
           ON CONFLICT (id) DO NOTHING""",
        domain_id,
    )
    await conn.execute(
        """INSERT INTO os_projects(id, domain_id, name, description, enabled) VALUES
           ($1, $3, 'admin', 'Admin project', true),
           ($2, $3, 'demo', 'Demo project', true)
           ON CONFLICT (id) DO NOTHING""",
        admin_project,
        demo_project,
        domain_id,
    )
    await conn.execute(
        """INSERT INTO os_users(id, domain_id, name, password_hash, enabled) VALUES
           ($1, $3, 'admin', $4, true),
           ($2, $3, 'demo', $4, true)
           ON CONFLICT (id) DO NOTHING""",
        admin_user,
        demo_user,
        domain_id,
        pw,
    )
    await conn.execute(
        """INSERT INTO os_roles(id, name) VALUES
           ($1, 'admin'), ($2, 'member')
           ON CONFLICT (id) DO NOTHING""",
        role_admin,
        role_member,
    )
    await conn.execute(
        """INSERT INTO os_role_assignments(id, role_id, user_id, project_id) VALUES
           ($1, $3, $5, $7),
           ($2, $4, $6, $8)
           ON CONFLICT (role_id, user_id, project_id) DO NOTHING""",
        oid("assign:admin-admin"),
        oid("assign:demo-member"),
        role_admin,
        role_member,
        admin_user,
        demo_user,
        admin_project,
        demo_project,
    )
    # admin also admin on demo for convenience
    await conn.execute(
        """INSERT INTO os_role_assignments(id, role_id, user_id, project_id)
           VALUES($1, $2, $3, $4)
           ON CONFLICT (role_id, user_id, project_id) DO NOTHING""",
        oid("assign:admin-demo-admin"),
        role_admin,
        admin_user,
        demo_project,
    )

    flavors = [
        ("1", "m1.tiny", 1, 512, 1),
        ("2", "m1.small", 1, 2048, 20),
        ("3", "m1.medium", 2, 4096, 40),
        ("4", "m1.large", 4, 8192, 80),
    ]
    for fid, name, vcpus, ram, disk in flavors:
        await conn.execute(
            """INSERT INTO os_flavors(id, name, vcpus, ram, disk, is_public)
               VALUES($1, $2, $3, $4, $5, true)
               ON CONFLICT (id) DO NOTHING""",
            fid,
            name,
            vcpus,
            ram,
            disk,
        )

    cirros = oid("image:cirros")
    ubuntu = oid("image:ubuntu")
    await conn.execute(
        """INSERT INTO os_images(id, name, status, visibility, size, disk_format,
               container_format, owner_project_id)
           VALUES
           ($1, 'cirros', 'active', 'public', 13287936, 'qcow2', 'bare', $3),
           ($2, 'ubuntu-22.04', 'active', 'public', 400000000, 'qcow2', 'bare', $3)
           ON CONFLICT (id) DO NOTHING""",
        cirros,
        ubuntu,
        admin_project,
    )

    demo_net = oid("net:demo-net")
    await conn.execute(
        """INSERT INTO os_networks(id, project_id, name, status, shared, admin_state_up)
           VALUES($1, $2, 'demo-net', 'ACTIVE', false, true)
           ON CONFLICT (id) DO NOTHING""",
        demo_net,
        demo_project,
    )
    demo_subnet = oid("subnet:demo-subnet")
    await conn.execute(
        """INSERT INTO os_subnets(id, network_id, project_id, name, cidr, ip_version, gateway_ip)
           VALUES($1, $2, $3, 'demo-subnet', '10.0.0.0/24', 4, '10.0.0.1')
           ON CONFLICT (id) DO NOTHING""",
        demo_subnet,
        demo_net,
        demo_project,
    )

    vol = oid("volume:demo-vol")
    await conn.execute(
        """INSERT INTO os_volumes(id, project_id, name, status, size, volume_type, bootable)
           VALUES($1, $2, 'demo-volume', 'available', 10, 'lvmdriver-1', false)
           ON CONFLICT (id) DO NOTHING""",
        vol,
        demo_project,
    )

    server = oid("server:demo-1")
    await conn.execute(
        """INSERT INTO os_servers(id, project_id, user_id, name, status, flavor_id, image_id, addresses, metadata)
           VALUES($1, $2, $3, 'demo-instance', 'ACTIVE', '2', $4,
                  $5::jsonb, $6::jsonb)
           ON CONFLICT (id) DO NOTHING""",
        server,
        demo_project,
        demo_user,
        cirros,
        '{"demo-net":[{"OS-EXT-IPS-MAC:mac_addr":"fa:16:3e:00:00:01","version":4,"addr":"10.0.0.12","OS-EXT-IPS:type":"fixed"}]}',
        '{"env":"lab","_tags":["lab","env","demo"]}',
    )

    await seed_openstack_extras(conn)

    from app.openstack.pack_seed import seed_pack_surface_samples
    from app.openstack.seed_discovery import seed_discovery_documents

    await seed_discovery_documents(conn)
    await seed_pack_surface_samples(conn, per_type=3)

    # Minimal topology tables (011+) — ignore if migration not applied yet.
    try:
        await conn.execute(
            """INSERT INTO os_availability_zones(name, zone_state)
               VALUES('nova', '{"available": true}'::jsonb)
               ON CONFLICT (name) DO NOTHING"""
        )
        await conn.execute(
            """INSERT INTO os_hypervisors(
                   id, hypervisor_hostname, state, status, host_ip, vcpus, vcpus_used,
                   memory_mb, memory_mb_used, local_gb, local_gb_used, running_vms,
                   service_host, availability_zone)
               VALUES(1,'compute-1','up','enabled','10.20.0.10',64,1,262144,2048,2000,20,1,'compute-1','nova')
               ON CONFLICT (id) DO NOTHING"""
        )
        await conn.execute(
            """INSERT INTO os_demo_meta(key, value) VALUES('profile','minimal')
               ON CONFLICT (key) DO UPDATE SET value=EXCLUDED.value, updated_at=now()"""
        )
    except Exception:
        pass

    return {
        "domain": "Default",
        "users": ["admin", "demo"],
        "password": password,
        "projects": ["admin", "demo"],
        "sample_server": "demo-instance",
        "profile": "minimal",
    }


async def seed_openstack_extras(conn: Connection) -> None:
    """Seed routers, SG, ironic nodes, LB, heat stack, swift objects, generic services."""

    import json
    from uuid import uuid4

    demo_project = oid("project:demo")
    admin_project = oid("project:admin")
    demo_user = oid("user:demo")

    # default security group
    sg = oid("sg:demo-default")
    await conn.execute(
        """INSERT INTO os_security_groups(id, project_id, name, description)
           VALUES($1,$2,'default','Default security group') ON CONFLICT (id) DO NOTHING""",
        sg,
        demo_project,
    )
    for direction, proto, pmin, pmax, prefix in (
        ("egress", None, None, None, None),
        ("ingress", "tcp", 22, 22, "0.0.0.0/0"),
        ("ingress", "icmp", None, None, "0.0.0.0/0"),
    ):
        await conn.execute(
            """INSERT INTO os_security_group_rules(id, security_group_id, project_id, direction, ethertype, protocol, port_range_min, port_range_max, remote_ip_prefix)
               VALUES($1,$2,$3,$4,'IPv4',$5,$6,$7,$8) ON CONFLICT (id) DO NOTHING""",
            oid(f"sgrule:{direction}:{proto}:{pmin}"),
            sg,
            demo_project,
            direction,
            proto,
            pmin,
            pmax,
            prefix,
        )

    await conn.execute(
        """INSERT INTO os_routers(id, project_id, name, status, admin_state_up, external_gateway_info)
           VALUES($1,$2,'demo-router','ACTIVE',true,NULL) ON CONFLICT (id) DO NOTHING""",
        oid("router:demo"),
        demo_project,
    )

    await conn.execute(
        """INSERT INTO os_nodes(id, name, driver, provision_state, power_state, resource_class, properties, driver_info, ports)
           VALUES($1,'baremetal-1','ipmi','available','power off','baremetal',
                  '{"cpus":64,"memory_mb":262144,"local_gb":2000}'::jsonb,'{}'::jsonb,'[]'::jsonb)
           ON CONFLICT (id) DO NOTHING""",
        oid("node:baremetal-1"),
    )

    await conn.execute(
        """INSERT INTO os_loadbalancers(id, project_id, name, description, vip_address, provisioning_status, operating_status)
           VALUES($1,$2,'demo-lb','Seed LB','10.0.0.50','ACTIVE','ONLINE')
           ON CONFLICT (id) DO NOTHING""",
        oid("lb:demo"),
        demo_project,
    )

    await conn.execute(
        """INSERT INTO os_stacks(id, project_id, stack_name, stack_status, description, template, parameters, outputs)
           VALUES($1,$2,'demo-stack','CREATE_COMPLETE','Seed stack','{"heat_template_version":"2015-04-30"}'::jsonb,'{}'::jsonb,'[]'::jsonb)
           ON CONFLICT (id) DO NOTHING""",
        oid("stack:demo"),
        demo_project,
    )

    for project in (demo_project, admin_project):
        account = f"AUTH_{project}"
        await conn.execute(
            """INSERT INTO os_swift_containers(account, name, meta)
               VALUES($1,'images','{}'::jsonb) ON CONFLICT DO NOTHING""",
            account,
        )
        await conn.execute(
            """INSERT INTO os_swift_objects(id, account, container, name, content_type, bytes, body, meta)
               VALUES($1,$2,'images','readme.txt','text/plain',12,$3,'{}'::jsonb)
               ON CONFLICT (account, container, name) DO NOTHING""",
            oid(f"swift:readme:{account}"),
            account,
            b"hello swift\n",
        )

    for user_id, key_name in ((demo_user, "demo-key"), (oid("user:admin"), "admin-key")):
        await conn.execute(
            """INSERT INTO os_keypairs(name, user_id, fingerprint, public_key, type)
               VALUES($1,$2,$3,$4,'ssh')
               ON CONFLICT DO NOTHING""",
            key_name,
            user_id,
            f"https://example.invalid/{key_name}",
            f"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC {key_name}@lab",
        )

    # Sample objects for every remaining service collection
    samples = [
        (
            "barbican",
            "secret",
            "demo-secret",
            {"payload_content_type": "text/plain", "secret_type": "passphrase"},
        ),
        (
            "manila",
            "share",
            "demo-share",
            {"size": 10, "share_proto": "NFS", "status": "available"},
        ),
        (
            "designate",
            "zone",
            "example.lab.",
            {"email": "hostmaster@example.lab", "ttl": 3600, "type": "PRIMARY"},
        ),
        (
            "magnum",
            "cluster",
            "demo-k8s",
            {"coe": "kubernetes", "status": "CREATE_COMPLETE", "node_count": 2},
        ),
        ("zun", "container", "demo-ctr", {"image": "cirros", "status": "Running"}),
        (
            "trove",
            "instance",
            "demo-db",
            {"datastore": {"type": "mysql", "version": "8.0"}, "status": "ACTIVE"},
        ),
        (
            "mistral",
            "workflow",
            "demo-wf",
            {"input": {}, "definition": "version: '2.0'\ndemo_wf:\n  tasks: {}"},
        ),
        (
            "aodh",
            "alarm",
            "cpu-high",
            {"type": "threshold", "state": "ok", "severity": "avg(cpu)>80"},
        ),
        (
            "freezer",
            "job",
            "daily-backup",
            {"description": "lab backup job", "status": "scheduled"},
        ),
        (
            "blazar",
            "lease",
            "demo-lease",
            {"start_date": "2026-01-01T00:00:00", "end_date": "2026-12-31T00:00:00"},
        ),
        ("vitrage", "alarm", "host-down", {"type": "host", "state": "critical"}),
        (
            "masakari",
            "segment",
            "az-segment",
            {"recovery_method": "auto", "service_type": "compute"},
        ),
        ("tacker", "vnf", "demo-vnf", {"status": "ACTIVE", "vnfd_id": "vnfd-1"}),
        ("adjutant", "task", "invite-user", {"task_type": "create_user", "status": "open"}),
        ("adjutant", "token", "adj-token-demo", {"status": "active"}),
        ("adjutant", "notification", "adj-notif-demo", {"status": "sent"}),
        (
            "adjutant",
            "status",
            "adj-status-demo",
            {"status": "UP", "service": "adjutant", "state": "up"},
        ),
        ("cloudkitty", "hashmap_service", "compute", {"name": "compute"}),
        (
            "heat-cfn",
            "stack",
            "demo-cfn",
            {"StackName": "demo-cfn", "StackStatus": "CREATE_COMPLETE"},
        ),
        ("watcher", "audit", "demo-audit", {"state": "SUCCEEDED"}),
        ("zaqar", "queue", "demo-queue", {"_default_message_ttl": 3600}),
        (
            "masakari",
            "host",
            "compute-1",
            {"name": "compute-1", "type": "compute", "reserved": False},
        ),
        ("designate", "recordset", "www", {"type": "A", "records": ["203.0.113.10"], "ttl": 3600}),
        # Extra types that pack lists expose and previously relied on lazy fixtures.
        ("barbican", "container", "demo-container", {"type": "generic", "status": "ACTIVE"}),
        ("barbican", "order", "demo-order", {"type": "key", "status": "ACTIVE"}),
        ("barbican", "secret_store", "demo-store", {"status": "ACTIVE"}),
        ("manila", "share_type", "default", {"is_public": True}),
        ("manila", "share_network", "demo-share-net", {"status": "active"}),
        ("manila", "share_snapshot", "demo-share-snap", {"status": "available", "size": 10}),
        ("manila", "share_server", "demo-share-srv", {"status": "active"}),
        ("manila", "security_service", "demo-sec-svc", {"type": "ldap", "status": "new"}),
        ("manila", "share_group", "demo-share-grp", {"status": "available"}),
        ("manila", "share_replica", "demo-share-rep", {"status": "available"}),
        ("designate", "tld", "lab", {"name": "lab"}),
        ("designate", "blacklist", "bad-pattern", {"pattern": "^bad\\..*"}),
        ("designate", "pool", "default", {"name": "default"}),
        ("designate", "service_status", "dns-central", {"status": "UP"}),
        ("magnum", "clustertemplate", "k8s-default", {"coe": "kubernetes", "image_id": "cirros"}),
        ("magnum", "certificate", "demo-cert", {"cluster_uuid": "demo-k8s"}),
        ("zun", "capsule", "demo-capsule", {"status": "Running", "cpu": 1, "memory": 512}),
        ("zun", "host", "zun-compute-1", {"hostname": "zun-compute-1", "state": "up"}),
        ("zun", "image", "nginx", {"image": "nginx", "status": "ACTIVE"}),
        (
            "zun",
            "service",
            "zun-compute",
            {"host": "zun-1", "binary": "zun-compute", "state": "up"},
        ),
        ("trove", "backup", "demo-db-bak", {"status": "COMPLETED", "size": 1.5}),
        ("trove", "cluster", "demo-db-cl", {"instance_count": 3}),
        ("trove", "configuration", "demo-db-cfg", {"datastore_name": "mysql"}),
        ("trove", "datastore", "mysql", {"name": "mysql", "version": "8.0"}),
        ("mistral", "action", "demo-action", {"is_system": False}),
        ("mistral", "cron_trigger", "hourly", {"pattern": "0 * * * *"}),
        ("mistral", "execution", "demo-exec", {"state": "SUCCESS"}),
        ("mistral", "task", "demo-task", {"state": "SUCCESS"}),
        ("mistral", "workbook", "demo-wb", {"definition": "version: '2.0'"}),
        ("aodh", "quota", "aodh-default", {"alarm": 100}),
        ("freezer", "action", "demo-freezer-action", {"status": "available"}),
        ("freezer", "backup", "demo-freezer-bak", {"status": "available"}),
        ("freezer", "client", "demo-freezer-client", {"status": "available"}),
        ("freezer", "session", "demo-freezer-session", {"status": "scheduled"}),
        ("blazar", "floatingip", "blazar-fip", {"floating_ip_address": "198.51.100.10"}),
        ("blazar", "host", "blazar-host-1", {"status": "available"}),
        ("vitrage", "event", "host-down-evt", {"type": "compute.host.down"}),
        ("vitrage", "resource", "vit-server", {"type": "nova.instance", "state": "ACTIVE"}),
        ("vitrage", "template", "vit-tmpl", {"type": "standard", "status": "active"}),
        ("vitrage", "topology", "vit-topo", {"nodes": [], "links": []}),
        ("masakari", "notification", "demo-notif", {"status": "finished"}),
        ("tacker", "vim", "demo-vim", {"type": "openstack", "status": "REACHABLE"}),
        ("tacker", "vnf_instance", "demo-vnf-inst", {"instantiationState": "INSTANTIATED"}),
        ("tacker", "vnf_package", "demo-vnf-pkg", {"onboardingState": "ONBOARDED"}),
        ("tacker", "vnfd", "demo-vnfd", {"name": "demo-vnfd"}),
        ("cloudkitty", "dataframes", "df-0", {"period": "3600"}),
        ("cloudkitty", "hashmap_field", "field-0", {"name": "field-0"}),
        ("cloudkitty", "report_summary", "summary-0", {"tenant_id": "demo"}),
        ("watcher", "action", "w-action-0", {"state": "SUCCEEDED"}),
        ("watcher", "action_plan", "ap-0", {"state": "SUCCEEDED"}),
        ("watcher", "audit_template", "at-0", {"goal": "server_consolidation"}),
        ("watcher", "goal", "goal-0", {"display_name": "Goal 0"}),
        ("watcher", "scoring_engine", "se-0", {"description": "engine 0"}),
        ("watcher", "service", "wsvc-0", {"host": "watcher-0", "status": "ACTIVE"}),
        ("watcher", "strategy", "strategy-0", {"goal_uuid": "goal-0"}),
        ("ironic", "driver", "ipmi", {"name": "ipmi", "hosts": ["simulator"], "type": "classic"}),
        (
            "ironic",
            "driver",
            "redfish",
            {"name": "redfish", "hosts": ["simulator"], "type": "classic"},
        ),
        (
            "neutron",
            "agent",
            "l3-agent",
            {"agent_type": "L3 agent", "host": "network-1", "alive": True, "admin_state_up": True},
        ),
        (
            "neutron",
            "agent",
            "ovs-agent",
            {
                "agent_type": "Open vSwitch agent",
                "host": "compute-1",
                "alive": True,
                "admin_state_up": True,
            },
        ),
        (
            "nova",
            "console_output",
            "default-console",
            {"output": "Booting...\nSimulator console\n"},
        ),
        (
            "nova",
            "console",
            "default-vnc",
            {"type": "novnc", "url": "https://127.0.0.1:6080/vnc_auto.html?token=simulator"},
        ),
        (
            "nova",
            "migration",
            "demo-mig",
            {
                "status": "completed",
                "migration_type": "migration",
                "source_compute": "compute-1",
                "dest_compute": "compute-2",
                "instance_uuid": str(oid("server:demo-1")),
            },
        ),
        (
            "nova",
            "server_topology",
            "demo-topo",
            {
                "server_id": str(oid("server:demo-1")),
                "nodes": [
                    {
                        "vcpu_set": [0],
                        "siblings": [[0]],
                        "host_node": 0,
                        "memory_mb": 2048,
                        "cpu_pinning": {},
                    }
                ],
                "pagesize_kb": 4,
                "host": "compute-1",
            },
        ),
        (
            "nova",
            "server_password",
            "demo-password",
            {"server_id": str(oid("server:demo-1")), "password": ""},
        ),
        (
            "placement",
            "resource_provider",
            "rp-0",
            {"name": "compute-1", "generation": 1},
        ),
        (
            "placement",
            "allocation",
            "alloc-demo",
            {
                "consumer_uuid": str(oid("server:demo-1")),
                "resource_provider": str(oid("placement:resource_provider:rp-0")),
                "resource_provider_id": str(oid("placement:resource_provider:rp-0")),
                "resources": {"VCPU": 1, "MEMORY_MB": 2048, "DISK_GB": 20},
                "consumer_generation": 1,
            },
        ),
        (
            "placement",
            "inventory",
            "inv-demo",
            {
                "resource_provider": str(oid("placement:resource_provider:rp-0")),
                "resource_provider_id": str(oid("placement:resource_provider:rp-0")),
                "resource_class": "VCPU",
                "total": 64,
                "reserved": 0,
            },
        ),
        (
            "placement",
            "aggregate",
            "agg-demo",
            {
                "name": "agg-demo",
                "resource_provider": str(oid("placement:resource_provider:rp-0")),
                "resource_provider_id": str(oid("placement:resource_provider:rp-0")),
            },
        ),
        (
            "nova",
            "console_auth_token",
            "demo-cat",
            {
                "token": "demo-console-token",
                "console_type": "novnc",
                "host": "127.0.0.1",
                "port": 6080,
                "internal_access_path": None,
            },
        ),
    ]
    for service, rtype, name, data in samples:
        item_id = oid(f"{service}:{rtype}:{name}")
        payload = {"id": str(item_id), "name": name, "status": data.get("status", "ACTIVE"), **data}
        await conn.execute(
            """INSERT INTO os_api_objects(id, service, resource_type, project_id, name, status, data)
               VALUES($1,$2,$3,$4,$5,$6,$7::jsonb)
               ON CONFLICT (id) DO NOTHING""",
            item_id,
            service,
            rtype,
            None,  # visible to any project-scoped token
            name,
            payload["status"],
            json.dumps(payload),
        )
