# Path: src/schemas/messages.py
# class SmsNumbersModel(BaseModel):
#     numbers: Dict[int, str]
#     country_code: constr(min_length=2, max_length=2) = 'GB'
# 
# class SmsSendMethod(str, Enum):
#     sms_messagebird = 'sms-messagebird'
#     sms_test = 'sms-test'
# 
# class SmsSendModel(BaseModel):
#     uid: constr(min_length=20, max_length=40)
#     main_template: str
#     company_code: str
#     cost_limit: float = None
#     country_code: constr(min_length=2, max_length=2) = 'GB'
#     from_name: constr(min_length=1, max_length=11) = 'Morpheus'
#     method: SmsSendMethod = ...
#     tags: List[str] = []
#     context: dict = {}
#     recipients: List[SmsRecipientModel] = ...
# 
# Path: src/utils.py
# class AdminAuth:
#     def __init__(self, request: Request):
#         if request.headers.get('Authorization', '') != glove.settings.auth_key:
#             raise HttpForbidden('Invalid token')
# 
# Path: src/views/utils.py
# async def get_or_create_company(conn: BuildPgConnection, company_code):
#     company_id = await conn.fetchval_b('select id from companies where code = :code', code=company_code)
#     if not company_id:
#         company_id = await conn.fetchval_b(
#             'insert into companies (code) values :values returning id', values=Values(code=company_code)
#         )
#     return company_id
# 
# async def get_sms_spend(conn: BuildPgConnection, *, company_id, method, start, end):
#     # noinspection PyChainedComparisons
#     where = Where(
#         (V('method') == method) & (V('company_id') == company_id) & (start <= V('send_ts')) & (V('send_ts') < end)
#     )
#     return await conn.fetchval_b('select sum(cost) from messages :where', where=where)
# 
# Path: src/worker/sms.py
# def validate_number(number, country, include_description=True) -> Optional[Number]:
#     try:
#         p = parse_number(number, country)
#     except NumberParseException:
#         return
# 
#     if not is_valid_number(p):
#         return
# 
#     is_mobile = number_type(p) in MOBILE_NUMBER_TYPES
#     descr = None
#     if include_description:
#         country = country_name_for_number(p, 'en')
#         region = description_for_number(p, 'en')
#         descr = country if country == region else f'{region}, {country}'
# 
#     return Number(
#         number=format_number(p, PhoneNumberFormat.E164),
#         country_code=f'{p.country_code}',
#         number_formatted=format_number(p, PhoneNumberFormat.INTERNATIONAL),
#         descr=descr,
#         is_mobile=is_mobile,
#     )


from dataclasses import asdict
from buildpg import Values
from buildpg.asyncpg import BuildPgConnection
from datetime import datetime, timezone
from fastapi import APIRouter, Body, Depends
from foxglove import glove
from foxglove.db.middleware import get_db
from foxglove.exceptions import HttpConflict, HttpNotFound
from foxglove.route_class import KeepBodyAPIRoute
from starlette.responses import JSONResponse
from typing import Tuple
from src.schemas.messages import SmsNumbersModel, SmsSendMethod, SmsSendModel
from src.utils import AdminAuth
from src.views.utils import get_or_create_company, get_sms_spend
from src.worker.sms import validate_number
import logging
    if not company_id:
        raise HttpNotFound('company not found')
    start = datetime.strptime(data['start'], '%Y-%m-%d')
    end = datetime.strptime(data['end'], '%Y-%m-%d')
    spend = await get_sms_spend(conn, company_id=company_id, method=method, start=start, end=end)
    return {
        'company': company_code,
        'start': start.strftime('%Y-%m-%d'),
        'end': end.strftime('%Y-%m-%d'),
        'spend': spend or 0,
    }


def month_interval() -> Tuple[datetime, datetime]:
    n = datetime.utcnow().replace(tzinfo=timezone.utc)
    return n.replace(day=1, hour=0, minute=0, second=0, microsecond=0), n


@app.post('/send/sms/')
async def send_sms(m: SmsSendModel, conn=Depends(get_db)):
    group_key = f'group:{m.uid}'
    v = await glove.redis.incr(group_key)
    if v > 1:
        raise HttpConflict(f'Send group with id "{m.uid}" already exists\n')
    await glove.redis.expire(group_key, 86400)

    month_spend = None
    company_id = await get_or_create_company(conn, m.company_code)
    if m.cost_limit is not None:
        start, end = month_interval()

# Path: src/schemas/messages.py
# class SmsNumbersModel(BaseModel):
#     numbers: Dict[int, str]
#     country_code: constr(min_length=2, max_length=2) = 'GB'
# 
# class SmsSendMethod(str, Enum):
#     sms_messagebird = 'sms-messagebird'
#     sms_test = 'sms-test'
# 
# class SmsSendModel(BaseModel):
#     uid: constr(min_length=20, max_length=40)
#     main_template: str
#     company_code: str
#     cost_limit: float = None
#     country_code: constr(min_length=2, max_length=2) = 'GB'
#     from_name: constr(min_length=1, max_length=11) = 'Morpheus'
#     method: SmsSendMethod = ...
#     tags: List[str] = []
#     context: dict = {}
#     recipients: List[SmsRecipientModel] = ...
# 
# Path: src/utils.py
# class AdminAuth:
#     def __init__(self, request: Request):
#         if request.headers.get('Authorization', '') != glove.settings.auth_key:
#             raise HttpForbidden('Invalid token')
# 
# Path: src/views/utils.py
# async def get_or_create_company(conn: BuildPgConnection, company_code):
#     company_id = await conn.fetchval_b('select id from companies where code = :code', code=company_code)
#     if not company_id:
#         company_id = await conn.fetchval_b(
#             'insert into companies (code) values :values returning id', values=Values(code=company_code)
#         )
#     return company_id
# 
# async def get_sms_spend(conn: BuildPgConnection, *, company_id, method, start, end):
#     # noinspection PyChainedComparisons
#     where = Where(
#         (V('method') == method) & (V('company_id') == company_id) & (start <= V('send_ts')) & (V('send_ts') < end)
#     )
#     return await conn.fetchval_b('select sum(cost) from messages :where', where=where)
# 
# Path: src/worker/sms.py
# def validate_number(number, country, include_description=True) -> Optional[Number]:
#     try:
#         p = parse_number(number, country)
#     except NumberParseException:
#         return
# 
#     if not is_valid_number(p):
#         return
# 
#     is_mobile = number_type(p) in MOBILE_NUMBER_TYPES
#     descr = None
#     if include_description:
#         country = country_name_for_number(p, 'en')
#         region = description_for_number(p, 'en')
#         descr = country if country == region else f'{region}, {country}'
# 
#     return Number(
#         number=format_number(p, PhoneNumberFormat.E164),
#         country_code=f'{p.country_code}',
#         number_formatted=format_number(p, PhoneNumberFormat.INTERNATIONAL),
#         descr=descr,
#         is_mobile=is_mobile,
#     )


# Path: src/views/sms.py
from dataclasses import asdict
from buildpg import Values
from buildpg.asyncpg import BuildPgConnection
from datetime import datetime, timezone
from fastapi import APIRouter, Body, Depends
from foxglove import glove
from foxglove.db.middleware import get_db
from foxglove.exceptions import HttpConflict, HttpNotFound
from foxglove.route_class import KeepBodyAPIRoute
from starlette.responses import JSONResponse
from typing import Tuple
from src.schemas.messages import SmsNumbersModel, SmsSendMethod, SmsSendModel
from src.utils import AdminAuth
from src.views.utils import get_or_create_company, get_sms_spend
from src.worker.sms import validate_number
import logging

    if not company_id:
        raise HttpNotFound('company not found')
    start = datetime.strptime(data['start'], '%Y-%m-%d')
    end = datetime.strptime(data['end'], '%Y-%m-%d')
    spend = await get_sms_spend(conn, company_id=company_id, method=method, start=start, end=end)
    return {
        'company': company_code,
        'start': start.strftime('%Y-%m-%d'),
        'end': end.strftime('%Y-%m-%d'),
        'spend': spend or 0,
    }


def month_interval() -> Tuple[datetime, datetime]:
    n = datetime.utcnow().replace(tzinfo=timezone.utc)
    return n.replace(day=1, hour=0, minute=0, second=0, microsecond=0), n


@app.post('/send/sms/')
async def send_sms(m: SmsSendModel, conn=Depends(get_db)):
    group_key = f'group:{m.uid}'
    v = await glove.redis.incr(group_key)
    if v > 1:
        raise HttpConflict(f'Send group with id "{m.uid}" already exists\n')
    await glove.redis.expire(group_key, 86400)

    month_spend = None
    company_id = await get_or_create_company(conn, m.company_code)
    if m.cost_limit is not None:
        start, end = month_interval()

        month_spend = await get_sms_spend(conn, company_id=company_id, start=start, end=end, method=m.method) or 0