"""Phase 1 initial schema

Revision ID: 001_initial
Revises: None
Create Date: 2026-06-30
"""
from typing import Sequence, Union

from alembic import op
import sqlalchemy as sa
from sqlalchemy.dialects.postgresql import JSONB, UUID

revision: str = "001_initial"
down_revision: Union[str, None] = None
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None


def upgrade() -> None:
    op.create_table(
        "erp_systems",
        sa.Column("id", UUID(as_uuid=True), primary_key=True),
        sa.Column("name", sa.String(255), nullable=False),
        sa.Column("erp_type", sa.String(50), nullable=False, index=True),
        sa.Column("version", sa.String(50)),
        sa.Column("base_url", sa.String(500)),
        sa.Column("auth_config", JSONB),
        sa.Column("status", sa.String(20), default="pending", index=True),
        sa.Column("metadata", JSONB),
        sa.Column("created_at", sa.DateTime(timezone=True), server_default=sa.func.now(), nullable=False),
        sa.Column("updated_at", sa.DateTime(timezone=True), server_default=sa.func.now(), onupdate=sa.func.now(), nullable=False),
    )

    op.create_table(
        "pharmacies",
        sa.Column("id", UUID(as_uuid=True), primary_key=True),
        sa.Column("code", sa.String(50), unique=True, nullable=False, index=True),
        sa.Column("name", sa.String(255), nullable=False),
        sa.Column("address", sa.String(500)),
        sa.Column("city", sa.String(100)),
        sa.Column("province", sa.String(100)),
        sa.Column("postal_code", sa.String(20)),
        sa.Column("country", sa.String(2), default="ES"),
        sa.Column("latitude", sa.Float),
        sa.Column("longitude", sa.Float),
        sa.Column("phone", sa.String(50)),
        sa.Column("email", sa.String(255)),
        sa.Column("opening_hours", JSONB),
        sa.Column("status", sa.String(20), default="pending", index=True),
        sa.Column("erp_type", sa.String(50)),
        sa.Column("erp_version", sa.String(50)),
        sa.Column("sync_strategy", sa.String(20), default="incremental"),
        sa.Column("sync_interval_minutes", sa.Integer, default=30),
        sa.Column("last_sync_at", sa.DateTime(timezone=True)),
        sa.Column("last_sync_status", sa.String(20)),
        sa.Column("metadata", JSONB),
        sa.Column("created_at", sa.DateTime(timezone=True), server_default=sa.func.now(), nullable=False),
        sa.Column("updated_at", sa.DateTime(timezone=True), server_default=sa.func.now(), onupdate=sa.func.now(), nullable=False),
    )
    op.create_index("ix_pharmacies_location", "pharmacies", ["latitude", "longitude"])
    op.create_index("ix_pharmacies_status_erp", "pharmacies", ["status", "erp_type"])

    op.create_table(
        "connectors",
        sa.Column("id", UUID(as_uuid=True), primary_key=True),
        sa.Column("erp_system_id", UUID(as_uuid=True), sa.ForeignKey("erp_systems.id"), nullable=False, index=True),
        sa.Column("pharmacy_id", UUID(as_uuid=True), sa.ForeignKey("pharmacies.id"), nullable=False, index=True),
        sa.Column("name", sa.String(255), nullable=False),
        sa.Column("connector_type", sa.String(50), nullable=False, index=True),
        sa.Column("version", sa.String(20), default="1.0.0"),
        sa.Column("config", JSONB),
        sa.Column("status", sa.String(20), default="pending", index=True),
        sa.Column("last_heartbeat_at", sa.DateTime(timezone=True)),
        sa.Column("last_error", sa.Text),
        sa.Column("metadata", JSONB),
        sa.Column("created_at", sa.DateTime(timezone=True), server_default=sa.func.now(), nullable=False),
        sa.Column("updated_at", sa.DateTime(timezone=True), server_default=sa.func.now(), onupdate=sa.func.now(), nullable=False),
        sa.UniqueConstraint("erp_system_id", "pharmacy_id", name="uq_connector_erp_pharmacy"),
    )

    op.add_column("pharmacies", sa.Column("connector_id", UUID(as_uuid=True), sa.ForeignKey("connectors.id"), nullable=True))
    op.create_index("ix_pharmacies_connector_id", "pharmacies", ["connector_id"])

    op.create_table(
        "connector_versions",
        sa.Column("id", UUID(as_uuid=True), primary_key=True),
        sa.Column("connector_id", UUID(as_uuid=True), sa.ForeignKey("connectors.id"), nullable=False, index=True),
        sa.Column("connector_type", sa.String(50), nullable=False, index=True),
        sa.Column("version", sa.String(20), nullable=False),
        sa.Column("changelog", sa.Text),
        sa.Column("download_url", sa.String(500)),
        sa.Column("checksum", sa.String(128)),
        sa.Column("is_latest", sa.Boolean, default=False, index=True),
        sa.Column("is_required", sa.Boolean, default=False),
        sa.Column("released_at", sa.DateTime(timezone=True)),
        sa.Column("created_at", sa.DateTime(timezone=True), server_default=sa.func.now(), nullable=False),
        sa.Column("updated_at", sa.DateTime(timezone=True), server_default=sa.func.now(), onupdate=sa.func.now(), nullable=False),
        sa.UniqueConstraint("connector_type", "version", name="uq_connector_version"),
    )

    op.create_table(
        "connector_configs",
        sa.Column("id", UUID(as_uuid=True), primary_key=True),
        sa.Column("connector_id", UUID(as_uuid=True), sa.ForeignKey("connectors.id"), nullable=False, index=True),
        sa.Column("key", sa.String(100), nullable=False),
        sa.Column("value", sa.Text, nullable=False),
        sa.Column("encrypted", sa.Boolean, default=False),
        sa.Column("description", sa.String(500)),
        sa.Column("created_at", sa.DateTime(timezone=True), server_default=sa.func.now(), nullable=False),
        sa.Column("updated_at", sa.DateTime(timezone=True), server_default=sa.func.now(), onupdate=sa.func.now(), nullable=False),
        sa.UniqueConstraint("connector_id", "key", name="uq_connector_config_key"),
    )

    op.create_table(
        "medications",
        sa.Column("id", UUID(as_uuid=True), primary_key=True),
        sa.Column("nregistro", sa.String(50), unique=True, nullable=False, index=True),
        sa.Column("name", sa.String(500), nullable=False, index=True),
        sa.Column("active_ingredient", sa.String(500)),
        sa.Column("dosage", sa.String(100)),
        sa.Column("form", sa.String(100)),
        sa.Column("atc_code", sa.String(20), index=True),
        sa.Column("prescription_required", sa.Boolean, default=False),
        sa.Column("manufacturer", sa.String(255)),
        sa.Column("metadata", JSONB),
        sa.Column("created_at", sa.DateTime(timezone=True), server_default=sa.func.now(), nullable=False),
        sa.Column("updated_at", sa.DateTime(timezone=True), server_default=sa.func.now(), onupdate=sa.func.now(), nullable=False),
    )

    op.create_table(
        "medication_catalog",
        sa.Column("id", UUID(as_uuid=True), primary_key=True),
        sa.Column("pharmacy_id", UUID(as_uuid=True), sa.ForeignKey("pharmacies.id"), nullable=False, index=True),
        sa.Column("medication_id", UUID(as_uuid=True), sa.ForeignKey("medications.id"), nullable=False, index=True),
        sa.Column("price", sa.Float),
        sa.Column("stock", sa.Integer, default=0),
        sa.Column("is_available", sa.Boolean, default=False, index=True),
        sa.Column("last_verified_at", sa.DateTime(timezone=True)),
        sa.Column("metadata", JSONB),
        sa.Column("created_at", sa.DateTime(timezone=True), server_default=sa.func.now(), nullable=False),
        sa.Column("updated_at", sa.DateTime(timezone=True), server_default=sa.func.now(), onupdate=sa.func.now(), nullable=False),
        sa.UniqueConstraint("pharmacy_id", "medication_id", name="uq_catalog_pharmacy_medication"),
    )

    op.create_table(
        "inventory_records",
        sa.Column("id", UUID(as_uuid=True), primary_key=True),
        sa.Column("pharmacy_id", UUID(as_uuid=True), sa.ForeignKey("pharmacies.id"), nullable=False, index=True),
        sa.Column("medication_id", UUID(as_uuid=True), sa.ForeignKey("medications.id"), nullable=False, index=True),
        sa.Column("stock", sa.Integer, default=0),
        sa.Column("reserved_stock", sa.Integer, default=0),
        sa.Column("available_stock", sa.Integer, default=0),
        sa.Column("min_stock", sa.Integer),
        sa.Column("max_stock", sa.Integer),
        sa.Column("last_updated_at", sa.DateTime(timezone=True), index=True),
        sa.Column("source", sa.String(100)),
        sa.Column("batch_id", sa.String(100)),
        sa.Column("metadata", JSONB),
        sa.Column("created_at", sa.DateTime(timezone=True), server_default=sa.func.now(), nullable=False),
        sa.Column("updated_at", sa.DateTime(timezone=True), server_default=sa.func.now(), onupdate=sa.func.now(), nullable=False),
        sa.UniqueConstraint("pharmacy_id", "medication_id", name="uq_inventory_pharmacy_medication"),
    )

    op.create_table(
        "inventory_history",
        sa.Column("id", UUID(as_uuid=True), primary_key=True),
        sa.Column("inventory_record_id", UUID(as_uuid=True), sa.ForeignKey("inventory_records.id"), nullable=False, index=True),
        sa.Column("pharmacy_id", UUID(as_uuid=True), sa.ForeignKey("pharmacies.id"), nullable=False, index=True),
        sa.Column("medication_id", UUID(as_uuid=True), sa.ForeignKey("medications.id"), nullable=False, index=True),
        sa.Column("previous_stock", sa.Integer, nullable=False),
        sa.Column("new_stock", sa.Integer, nullable=False),
        sa.Column("delta", sa.Integer, nullable=False),
        sa.Column("reason", sa.String(255)),
        sa.Column("source", sa.String(100)),
        sa.Column("created_at", sa.DateTime(timezone=True), server_default=sa.func.now(), nullable=False, index=True),
    )

    op.create_table(
        "technical_users",
        sa.Column("id", UUID(as_uuid=True), primary_key=True),
        sa.Column("username", sa.String(100), unique=True, nullable=False, index=True),
        sa.Column("email", sa.String(255)),
        sa.Column("full_name", sa.String(255)),
        sa.Column("password_hash", sa.String(255), nullable=False),
        sa.Column("role", sa.String(20), default="viewer", index=True),
        sa.Column("is_active", sa.Boolean, default=True, index=True),
        sa.Column("scopes", JSONB, default=list),
        sa.Column("last_login_at", sa.DateTime(timezone=True)),
        sa.Column("created_at", sa.DateTime(timezone=True), server_default=sa.func.now(), nullable=False),
        sa.Column("updated_at", sa.DateTime(timezone=True), server_default=sa.func.now(), onupdate=sa.func.now(), nullable=False),
    )

    op.create_table(
        "api_clients",
        sa.Column("id", UUID(as_uuid=True), primary_key=True),
        sa.Column("name", sa.String(255), nullable=False),
        sa.Column("description", sa.Text),
        sa.Column("owner_id", UUID(as_uuid=True), sa.ForeignKey("technical_users.id"), nullable=True, index=True),
        sa.Column("is_active", sa.Boolean, default=True, index=True),
        sa.Column("scopes", JSONB, default=list),
        sa.Column("rate_limit", sa.Integer),
        sa.Column("allowed_ips", JSONB, default=list),
        sa.Column("metadata", JSONB),
        sa.Column("created_at", sa.DateTime(timezone=True), server_default=sa.func.now(), nullable=False),
        sa.Column("updated_at", sa.DateTime(timezone=True), server_default=sa.func.now(), onupdate=sa.func.now(), nullable=False),
    )

    op.create_table(
        "api_keys",
        sa.Column("id", UUID(as_uuid=True), primary_key=True),
        sa.Column("api_client_id", UUID(as_uuid=True), sa.ForeignKey("api_clients.id"), nullable=False, index=True),
        sa.Column("key_prefix", sa.String(10), nullable=False, index=True),
        sa.Column("key_hash", sa.LargeBinary(64), nullable=False),
        sa.Column("name", sa.String(255), nullable=False),
        sa.Column("is_active", sa.Boolean, default=True, index=True),
        sa.Column("expires_at", sa.DateTime(timezone=True)),
        sa.Column("last_used_at", sa.DateTime(timezone=True)),
        sa.Column("created_at", sa.DateTime(timezone=True), server_default=sa.func.now(), nullable=False),
    )
    op.create_index("ix_api_keys_prefix_active", "api_keys", ["key_prefix", "is_active"])

    op.create_table(
        "reservations",
        sa.Column("id", UUID(as_uuid=True), primary_key=True),
        sa.Column("pharmacy_id", UUID(as_uuid=True), sa.ForeignKey("pharmacies.id"), nullable=False, index=True),
        sa.Column("medication_id", UUID(as_uuid=True), sa.ForeignKey("medications.id"), nullable=False, index=True),
        sa.Column("user_id", UUID(as_uuid=True), sa.ForeignKey("technical_users.id"), nullable=True, index=True),
        sa.Column("external_reference", sa.String(255)),
        sa.Column("quantity", sa.Integer, nullable=False),
        sa.Column("status", sa.String(20), default="pending", index=True),
        sa.Column("expires_at", sa.DateTime(timezone=True), index=True),
        sa.Column("confirmed_at", sa.DateTime(timezone=True)),
        sa.Column("cancelled_at", sa.DateTime(timezone=True)),
        sa.Column("idempotency_key", sa.String(255), unique=True, index=True),
        sa.Column("metadata", JSONB),
        sa.Column("created_at", sa.DateTime(timezone=True), server_default=sa.func.now(), nullable=False),
        sa.Column("updated_at", sa.DateTime(timezone=True), server_default=sa.func.now(), onupdate=sa.func.now(), nullable=False),
    )
    op.create_index("ix_reservations_pharmacy_status", "reservations", ["pharmacy_id", "status"])
    op.create_index("ix_reservations_expires", "reservations", ["expires_at"])

    op.create_table(
        "sync_jobs",
        sa.Column("id", UUID(as_uuid=True), primary_key=True),
        sa.Column("pharmacy_id", UUID(as_uuid=True), sa.ForeignKey("pharmacies.id"), nullable=False, index=True),
        sa.Column("connector_id", UUID(as_uuid=True), sa.ForeignKey("connectors.id"), nullable=False, index=True),
        sa.Column("strategy", sa.String(20), nullable=False),
        sa.Column("status", sa.String(20), default="pending", index=True),
        sa.Column("started_at", sa.DateTime(timezone=True)),
        sa.Column("completed_at", sa.DateTime(timezone=True)),
        sa.Column("items_total", sa.Integer),
        sa.Column("items_processed", sa.Integer),
        sa.Column("items_failed", sa.Integer),
        sa.Column("error_message", sa.Text),
        sa.Column("metadata", JSONB),
        sa.Column("created_at", sa.DateTime(timezone=True), server_default=sa.func.now(), nullable=False),
        sa.Column("updated_at", sa.DateTime(timezone=True), server_default=sa.func.now(), onupdate=sa.func.now(), nullable=False),
    )

    op.create_table(
        "sync_logs",
        sa.Column("id", UUID(as_uuid=True), primary_key=True),
        sa.Column("sync_job_id", UUID(as_uuid=True), sa.ForeignKey("sync_jobs.id"), nullable=False, index=True),
        sa.Column("level", sa.String(20), default="INFO", nullable=False),
        sa.Column("message", sa.Text, nullable=False),
        sa.Column("details", JSONB),
        sa.Column("created_at", sa.DateTime(timezone=True), server_default=sa.func.now(), nullable=False, index=True),
    )

    op.create_table(
        "audit_logs",
        sa.Column("id", UUID(as_uuid=True), primary_key=True),
        sa.Column("actor_id", UUID(as_uuid=True), index=True),
        sa.Column("actor_type", sa.String(50)),
        sa.Column("action", sa.String(100), nullable=False, index=True),
        sa.Column("resource_type", sa.String(100), nullable=False, index=True),
        sa.Column("resource_id", sa.String(255), index=True),
        sa.Column("old_value", JSONB),
        sa.Column("new_value", JSONB),
        sa.Column("ip_address", sa.String(45)),
        sa.Column("user_agent", sa.String(500)),
        sa.Column("request_id", sa.String(100), index=True),
        sa.Column("created_at", sa.DateTime(timezone=True), server_default=sa.func.now(), nullable=False, index=True),
    )
    op.create_index("ix_audit_logs_action_resource", "audit_logs", ["action", "resource_type"])
    op.create_index("ix_audit_logs_actor_created", "audit_logs", ["actor_id", "created_at"])


def downgrade() -> None:
    op.drop_table("audit_logs")
    op.drop_table("sync_logs")
    op.drop_table("sync_jobs")
    op.drop_table("reservations")
    op.drop_table("api_keys")
    op.drop_table("api_clients")
    op.drop_table("technical_users")
    op.drop_table("inventory_history")
    op.drop_table("inventory_records")
    op.drop_table("medication_catalog")
    op.drop_table("medications")
    op.drop_table("connector_configs")
    op.drop_table("connector_versions")
    op.drop_column("pharmacies", "connector_id")
    op.drop_table("connectors")
    op.drop_table("pharmacies")
    op.drop_table("erp_systems")
