import sqlalchemy as sa

from .columns import Column, DateTimeTZ, MoneyColumn
from .enums import (
    BillingType,
    CampaignType,
    CurrencyType,
    OrderOperationType,
    PaymentType,
    PlatformType,
)

_constraints_naming_convention = {
    "ix": "ix_%(table_name)s_%(column_0_label)s",
    "uq": "uq_%(table_name)s_%(column_0_name)s",
    "ck": "ck_%(table_name)s_%(constraint_name)s",
    "fk": "fk_%(table_name)s_%(column_0_name)s_%(referred_table_name)s",
    "pk": "pk_%(table_name)s",
}

metadata = sa.MetaData(naming_convention=_constraints_naming_convention)


clients = sa.Table(
    "clients",
    metadata,
    Column("id", sa.BigInteger, primary_key=True, autoincrement=False),
    Column("name", sa.String(length=256)),
    Column("email", sa.String(length=256)),
    Column("phone", sa.String(length=64), server_default=""),
    Column("account_manager_id", sa.BigInteger, nullable=True, index=True),
    Column("is_agency", sa.Boolean, server_default="FALSE"),
    Column("domain", sa.String(length=256), server_default=""),
    Column("partner_agency_id", sa.BigInteger, nullable=True, index=True),
    Column("has_accepted_offer", sa.Boolean, nullable=True, index=False),
)
sa.Index(
    "clients_id_btree_is_agency_true",
    "id",
    postgresql_where=(clients.c.is_agency.is_(True)),
    _table=clients,
)

agency_clients = sa.Table(
    "agency_clients",
    metadata,
    Column("id", sa.BigInteger, primary_key=True),
    Column("agency_id", sa.BigInteger, sa.ForeignKey("clients.id"), nullable=True),
    Column("client_id", sa.BigInteger, sa.ForeignKey("clients.id")),
)
_ = sa.Index(
    "agency_clients_unique_ind_agency_id_null",
    "client_id",
    unique=True,
    postgresql_where=(agency_clients.c.agency_id.is_(None)),
    _table=agency_clients,
)
_ = sa.Index(
    "agency_clients_unique_ind_agency_id_notnull",
    "agency_id",
    "client_id",
    unique=True,
    postgresql_where=(agency_clients.c.agency_id.isnot(None)),
    _table=agency_clients,
)

contracts = sa.Table(
    "contracts",
    metadata,
    Column("id", sa.BigInteger, primary_key=True, autoincrement=False),
    Column("external_id", sa.VARCHAR(length=64)),
    Column("client_id", sa.BigInteger, sa.ForeignKey("clients.id")),
    Column("currency", sa.Enum(CurrencyType)),
    Column("is_active", sa.Boolean),
    Column("date_start", sa.Date),
    Column("date_end", sa.Date, nullable=True),
    Column("payment_type", sa.Enum(PaymentType)),
    Column("preferred", sa.Boolean, server_default="FALSE"),
    sa.Index("contracts_client_id_btree_ind", "client_id"),
)

products = sa.Table(
    "products",
    metadata,
    Column("id", sa.BigInteger, primary_key=True),
    Column("oracle_id", sa.BigInteger),
    Column("service_id", sa.BigInteger, server_default="110"),
    Column("title", sa.String(length=256)),
    Column("act_text", sa.String(length=256)),
    Column("description", sa.Text),
    Column("currency", sa.Enum(CurrencyType)),
    Column("billing_type", sa.Enum(BillingType)),
    Column("vat_value", sa.Numeric()),
    Column("campaign_type", sa.Enum(CampaignType)),
    Column(
        "platform", sa.Enum(PlatformType)
    ),  # OBSOLETE, remove after new version deployed
    Column("platforms", sa.ARRAY(sa.Enum(PlatformType))),
    Column("comment", sa.String(length=512)),
    Column("available_for_agencies", sa.Boolean, default=True),
    Column("available_for_internal", sa.Boolean, default=True),
    Column("type", sa.String, default=""),
)

products_rules_versions = sa.Table(
    "product_rules_versions",
    metadata,
    Column("id", sa.BigInteger, primary_key=True),
    Column("product_id", sa.BigInteger, sa.ForeignKey("products.id")),
    Column("version", sa.Integer),
    Column("active_from", DateTimeTZ),
    Column("active_to", DateTimeTZ, nullable=True),
    Column(
        "billing_data", sa.dialects.postgresql.JSONB, server_default=sa.text("'{}'")
    ),
    MoneyColumn("min_budget"),
    Column(
        "cpm_filters", sa.dialects.postgresql.ARRAY(sa.String(length=128)), default=[]
    ),
    sa.CheckConstraint("min_budget >= 0.0", name="positive"),
    sa.CheckConstraint(
        "jsonb_typeof(billing_data) = 'object'", name="billing_data_object"
    ),
    sa.CheckConstraint(
        "active_from <= active_to", name="active_from_earlier_active_to"
    ),
    sa.Index(
        "product_rules_versions_product_id_version_btree_unique_ind",
        "product_id",
        "version",
        unique=True,
    ),
    sa.Index("product_rules_versions_product_id_btree_ind", "product_id"),
)

product_client_restrictions = sa.Table(
    "product_client_restrictions",
    metadata,
    Column("id", sa.BigInteger, primary_key=True),
    Column("product_id", sa.BigInteger, sa.ForeignKey("products.id")),
    Column("client_id", sa.BigInteger, sa.ForeignKey("clients.id")),
    sa.Index(
        "product_client_restrictions_unique_ind", "product_id", "client_id", unique=True
    ),
)

orders = sa.Table(
    "orders",
    metadata,
    Column("id", sa.BigInteger, primary_key=True),
    Column("external_id", sa.BigInteger),
    Column("service_id", sa.BigInteger, server_default="110"),
    Column("created_at", DateTimeTZ, server_default=sa.func.now()),
    Column(
        "tid", sa.BigInteger, server_default=sa.text("0")
    ),  # Balance monotonically increasing transaction id.
    Column("title", sa.String(length=256)),
    Column("act_text", sa.String(length=256)),
    Column("text", sa.Text()),
    Column("comment", sa.String(length=1024)),
    Column("client_id", sa.BigInteger, sa.ForeignKey("clients.id"), nullable=True),
    Column("agency_id", sa.BigInteger, sa.ForeignKey("clients.id"), nullable=True),
    Column("contract_id", sa.BigInteger, sa.ForeignKey("contracts.id"), nullable=True),
    Column("product_id", sa.BigInteger, sa.ForeignKey("products.id")),
    Column("parent_order_id", sa.BigInteger, sa.ForeignKey("orders.id"), nullable=True),
    Column("hidden", sa.Boolean, server_default="FALSE"),
    MoneyColumn("limit", server_default=sa.text("0")),
    MoneyColumn("consumed", server_default=sa.text("0")),
    sa.CheckConstraint("tid >= 0", name="tid_nonnegative"),
    sa.CheckConstraint('"limit" >= 0.0', name="limit_nonnegative"),
    sa.CheckConstraint("consumed >= 0.0", name="consumed_nonnegative"),
    sa.Index("orders_agency_id_client_id_btree_ind", "agency_id", "client_id"),
)


order_logs = sa.Table(
    "order_logs",
    metadata,
    Column("id", sa.BigInteger, primary_key=True),
    Column("created_at", DateTimeTZ, server_default=sa.func.now()),
    Column("op_type", sa.Enum(OrderOperationType)),
    Column("order_id", sa.BigInteger, sa.ForeignKey("orders.id")),
    MoneyColumn("amount"),
    MoneyColumn("limit"),
    MoneyColumn("consumed"),
    Column("billed_due_to", DateTimeTZ, nullable=True),
    sa.CheckConstraint('"limit" >= 0.0', name="limit_nonnegative"),
    sa.CheckConstraint("consumed >= 0.0", name="consumed_nonnegative"),
)
