import os
import pathlib
from datetime import datetime, date, time
from decimal import Decimal
from typing import Optional, List

from fastapi import APIRouter, Depends, HTTPException, status, File, UploadFile
from fastapi.encoders import jsonable_encoder
from sqlmodel import Field, SQLModel

from ..db import get_session

from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession

router = APIRouter()

cert_path = '/uploads/user/{user_id}/cert/'
avatar_path = '/uploads/user/{user_id}/avatar/'


class User(SQLModel, table=True):
    id: Optional[int] = Field(default=None, primary_key=True)
    state: str  # Statue: pending, active, inactive
    id_type_id: int
    id_number: str = None
    email = str
    email_verified_at: Optional[datetime] = None
    password: str
    remember_token: str
    hospital_id: Optional[int] = None
    hospital_node_id: Optional[int] = None
    discipline_id: int
    first_name_thai: str
    last_name_thai: str
    first_name_english: str
    last_name_english: str
    nickname: str
    birth_date: date
    gender: str
    academic_degree: str
    is_thai_address: bool
    address_house_number: str
    address_moo: str
    address_soi: str
    address_road: str
    address_tambon_id: Optional[int] = None
    address_amphoe_id: Optional[int] = None
    address_province_id: Optional[int] = None
    address_other: str
    latitude: Decimal
    longitude: Decimal
    potential: str
    avatar_path: str
    document_path: str
    policy_accept: bool
    created_at: datetime
    updated_at: datetime
    created_by: int
    updated_by: Optional[int] = None


class UserPhone(SQLModel, table=True):
    id: Optional[int] = Field(default=None, primary_key=True)
    user_id: int
    number: str
    detail: str
    receive_sms: bool
    created_at: datetime
    updated_at: datetime
    created_by: int
    updated_by: Optional[int] = None


class UserFeedback(SQLModel, table=True):
    id: Optional[int] = Field(default=None, primary_key=True)
    user_id: int
    feedback_type_id: Optional[int] = None
    detail: str
    created_at: datetime
    updated_at: datetime
    created_by: int
    updated_by: Optional[int] = None


class UserNotification(SQLModel, table=True):
    id: Optional[int] = Field(default=None, primary_key=True)
    user_id: int
    name: str
    detail: str
    is_read: bool
    created_at: datetime
    updated_at: datetime
    created_by: int
    updated_by: Optional[int] = None


class UserRole(SQLModel, table=True):
    id: Optional[int] = Field(default=None, primary_key=True)
    user_id: int
    role_id: int
    created_at: datetime
    updated_at: datetime
    created_by: int
    updated_by: Optional[int] = None


class UserSource(SQLModel, table=True):
    id: Optional[int] = Field(default=None, primary_key=True)
    name: str
    created_at: datetime
    created_by: int


class UserLog(SQLModel, table=True):
    id: Optional[int] = Field(default=None, primary_key=True)
    user_id: int


class Doctor(SQLModel, table=True):
    id: Optional[int] = Field(default=None, primary_key=True)
    user_id: int
    hospital_id: int
    discipline_id: int
    prefix: str
    first_name: str
    last_name: str
    created_at: datetime
    updated_at: datetime
    created_by: int
    updated_by: Optional[int] = None


class DoctorProcedureMap(SQLModel, table=True):
    id: Optional[int] = Field(default=None, primary_key=True)
    doctor_id: int
    procedure_id: int
    created_at: datetime
    updated_at: datetime
    created_by: int
    updated_by: Optional[int] = None


class Discipline(SQLModel, table=True):
    id: Optional[int] = Field(default=None, primary_key=True)
    discipline_group_id: int
    name: str
    created_at: datetime
    updated_at: datetime
    created_by: int
    updated_by: Optional[int] = None


class DisciplineGroup(SQLModel, table=True):
    id: Optional[int] = Field(default=None, primary_key=True)
    name: str
    created_at: datetime
    updated_at: datetime
    created_by: int
    updated_by: Optional[int] = None


class Role(SQLModel, table=True):
    id: Optional[int] = Field(default=None, primary_key=True)
    name: str
    created_at: datetime
    updated_at: datetime
    created_by: int
    updated_by: Optional[int] = None


class RoleModuleFunctionMap(SQLModel, table=True):
    id: Optional[int] = Field(default=None, primary_key=True)
    role_id: int
    module_function_id: int
    created_at: datetime
    updated_at: datetime
    created_by: int
    updated_by: Optional[int] = None


@router.post("/user", response_model=User)
async def create_user(user: User, session: AsyncSession = Depends(get_session)):
    # Add user
    session.add(user)
    await session.commit()
    await session.refresh(user)

    return user


@router.get("/user", response_model=List[User])
async def get_users(session: AsyncSession = Depends(get_session)):
    # Select all users
    statement = select(User)
    result = await session.execute(statement)
    users = result.scalars().all()
    return users


@router.post("/user/check_id/{id_type_id}/{id_number}", response_model=bool)
async def check_id_available(id_type_id: int, id_number: str, session: AsyncSession = Depends(get_session)):
    # Check id existence
    users = await session.execute(select(User).where(User.id_type_id == id_type_id).where(User.id_number == id_number))
    if users is None:
        return True
    return False


@router.get("/user/pending_num", response_model=int)
async def get_pending_user_num(session: AsyncSession = Depends(get_session)):
    # Get user with pending status
    users = await session.execute(select(User).where(User.state == "pending"))
    return len(users.scalars().all())


@router.get("/user/{user_id}", response_model=User)
async def get_user(user_id: int, session: AsyncSession = Depends(get_session)):
    # Get user with id
    users = await session.execute(select(User).where(User.id == user_id))
    user = users.scalars().first()
    return user


@router.put("/user/{user_id}", response_model=User)
async def update_user(user_id: int, user: User, session: AsyncSession = Depends(get_session)):
    # Get user with id
    statement = select(User).where(User.id == user_id)
    users = await session.execute(statement)

    # Update detail
    user_old = users.one()
    model = User(**user_old)
    update_data = user.dict(exclude_unset=True)
    updated_user = model.copy(update=update_data)
    user_old = jsonable_encoder(updated_user)

    # Commit to database
    await session.commit()

    return user_old


@router.delete("/user/{user_id}")
async def delete_user(user_id: int, session: AsyncSession = Depends(get_session)):
    # Check user existence
    statement = select(User).where(User.id == user_id)
    user = await session.execute(statement)

    # Not found error
    if not user:
        raise HTTPException(status_code=404, detail='User not found')

    user = user.scalars().one()

    # Delete
    await session.delete(user)
    await session.commit()

    return status.HTTP_200_OK


@router.post("/user/{user_id}/document")
async def upload_document(user_id: int, document: UploadFile = File(...), session: AsyncSession = Depends(get_session)):

    # File name
    file_dir = os.getcwd() + cert_path.format(user_id=user_id)
    file_path = file_dir + document.filename

    # Make directory if not exist
    try:
        if not os.path.exists(file_dir):
            pathlib.Path(file_dir).mkdir(parents=True, exist_ok=True)
    except Exception as e:
        print(e)

    # Write file
    with open(file_path, 'wb') as f:
        f.write(document.file.read())
        f.close()

    # Update user document path
    statement = select(User).where(User.id == user_id)
    users = await session.execute(statement)
    user_old = users.scalars().one()
    user_old.document_path = file_path

    await session.commit()

    return {'document_path': file_path}


@router.post("/user/{user_id}/accept")
async def accept_policy(session: AsyncSession = Depends(get_session)):
    return None


@router.post("/user/{user_id}/reset")
async def reset_password(session: AsyncSession = Depends(get_session)):
    return None


@router.post("/user/{user_id}/avatar")
async def upload_avatar(session: AsyncSession = Depends(get_session)):
    return None


@router.delete("/user/{user_id}/avatar")
async def delete_avatar(session: AsyncSession = Depends(get_session)):
    return None


@router.post("/user/{user_id}/role")
async def set_role(session: AsyncSession = Depends(get_session)):
    return None


@router.post("/user/feedback")
async def create_user_feedback(session: AsyncSession = Depends(get_session)):
    return None


@router.get("/user/feedback")
async def get_user_feedbacks(session: AsyncSession = Depends(get_session)):
    return None


@router.get("/user/feedback/{feedback_id}")
async def get_user_feedback(session: AsyncSession = Depends(get_session)):
    return None


@router.put("/user/feedback/{feedback_id}")
async def update_user_feedback(session: AsyncSession = Depends(get_session)):
    return None


@router.post("/user/doctor")
async def create_doctor(session: AsyncSession = Depends(get_session)):
    return None


@router.get("/user/doctor")
async def get_doctors(session: AsyncSession = Depends(get_session)):
    return None


@router.get("/user/doctor/{doctor_id}")
async def get_doctor(session: AsyncSession = Depends(get_session)):
    return None


@router.put("/user/doctor/{doctor_id}")
async def update_doctor(session: AsyncSession = Depends(get_session)):
    return None


@router.delete("/user/doctor/{doctor_id}")
async def delete_doctor(session: AsyncSession = Depends(get_session)):
    return None

fastapi.encoders.jsonable_encoder os.getcwd fastapi.File pathlib.Path os.path.exists fastapi.Depends sqlmodel.Field fastapi.APIRouter fastapi.HTTPException sqlalchemy.select
[((412, 423), 'fastapi.APIRouter', 'APIRouter', ([], {}), '()\n', (421, 423), False, 'from fastapi import APIRouter, Depends, HTTPException, status, File, UploadFile\n'), ((577, 614), 'sqlmodel.Field', 'Field', ([], {'default': 'None', 'primary_key': '(True)'}), '(default=None, primary_key=True)\n', (582, 614), False, 'from sqlmodel import Field, SQLModel\n'), ((1689, 1726), 'sqlmodel.Field', 'Field', ([], {'default': 'None', 'primary_key': '(True)'}), '(default=None, primary_key=True)\n', (1694, 1726), False, 'from sqlmodel import Field, SQLModel\n'), ((1973, 2010), 'sqlmodel.Field', 'Field', ([], {'default': 'None', 'primary_key': '(True)'}), '(default=None, primary_key=True)\n', (1978, 2010), False, 'from sqlmodel import Field, SQLModel\n'), ((2266, 2303), 'sqlmodel.Field', 'Field', ([], {'default': 'None', 'primary_key': '(True)'}), '(default=None, primary_key=True)\n', (2271, 2303), False, 'from sqlmodel import Field, SQLModel\n'), ((2540, 2577), 'sqlmodel.Field', 'Field', ([], {'default': 'None', 'primary_key': '(True)'}), '(default=None, primary_key=True)\n', (2545, 2577), False, 'from sqlmodel import Field, SQLModel\n'), ((2785, 2822), 'sqlmodel.Field', 'Field', ([], {'default': 'None', 'primary_key': '(True)'}), '(default=None, primary_key=True)\n', (2790, 2822), False, 'from sqlmodel import Field, SQLModel\n'), ((2945, 2982), 'sqlmodel.Field', 'Field', ([], {'default': 'None', 'primary_key': '(True)'}), '(default=None, primary_key=True)\n', (2950, 2982), False, 'from sqlmodel import Field, SQLModel\n'), ((3062, 3099), 'sqlmodel.Field', 'Field', ([], {'default': 'None', 'primary_key': '(True)'}), '(default=None, primary_key=True)\n', (3067, 3099), False, 'from sqlmodel import Field, SQLModel\n'), ((3397, 3434), 'sqlmodel.Field', 'Field', ([], {'default': 'None', 'primary_key': '(True)'}), '(default=None, primary_key=True)\n', (3402, 3434), False, 'from sqlmodel import Field, SQLModel\n'), ((3649, 3686), 'sqlmodel.Field', 'Field', ([], {'default': 'None', 'primary_key': '(True)'}), '(default=None, primary_key=True)\n', (3654, 3686), False, 'from sqlmodel import Field, SQLModel\n'), ((3908, 3945), 'sqlmodel.Field', 'Field', ([], {'default': 'None', 'primary_key': '(True)'}), '(default=None, primary_key=True)\n', (3913, 3945), False, 'from sqlmodel import Field, SQLModel\n'), ((4127, 4164), 'sqlmodel.Field', 'Field', ([], {'default': 'None', 'primary_key': '(True)'}), '(default=None, primary_key=True)\n', (4132, 4164), False, 'from sqlmodel import Field, SQLModel\n'), ((4363, 4400), 'sqlmodel.Field', 'Field', ([], {'default': 'None', 'primary_key': '(True)'}), '(default=None, primary_key=True)\n', (4368, 4400), False, 'from sqlmodel import Field, SQLModel\n'), ((4656, 4676), 'fastapi.Depends', 'Depends', (['get_session'], {}), '(get_session)\n', (4663, 4676), False, 'from fastapi import APIRouter, Depends, HTTPException, status, File, UploadFile\n'), ((4886, 4906), 'fastapi.Depends', 'Depends', (['get_session'], {}), '(get_session)\n', (4893, 4906), False, 'from fastapi import APIRouter, Depends, HTTPException, status, File, UploadFile\n'), ((4948, 4960), 'sqlalchemy.select', 'select', (['User'], {}), '(User)\n', (4954, 4960), False, 'from sqlalchemy import select\n'), ((5224, 5244), 'fastapi.Depends', 'Depends', (['get_session'], {}), '(get_session)\n', (5231, 5244), False, 'from fastapi import APIRouter, Depends, HTTPException, status, File, UploadFile\n'), ((5561, 5581), 'fastapi.Depends', 'Depends', (['get_session'], {}), '(get_session)\n', (5568, 5581), False, 'from fastapi import APIRouter, Depends, HTTPException, status, File, UploadFile\n'), ((5847, 5867), 'fastapi.Depends', 'Depends', (['get_session'], {}), '(get_session)\n', (5854, 5867), False, 'from fastapi import APIRouter, Depends, HTTPException, status, File, UploadFile\n'), ((6144, 6164), 'fastapi.Depends', 'Depends', (['get_session'], {}), '(get_session)\n', (6151, 6164), False, 'from fastapi import APIRouter, Depends, HTTPException, status, File, UploadFile\n'), ((6480, 6510), 'fastapi.encoders.jsonable_encoder', 'jsonable_encoder', (['updated_user'], {}), '(updated_user)\n', (6496, 6510), False, 'from fastapi.encoders import jsonable_encoder\n'), ((6681, 6701), 'fastapi.Depends', 'Depends', (['get_session'], {}), '(get_session)\n', (6688, 6701), False, 'from fastapi import APIRouter, Depends, HTTPException, status, File, UploadFile\n'), ((7182, 7191), 'fastapi.File', 'File', (['...'], {}), '(...)\n', (7186, 7191), False, 'from fastapi import APIRouter, Depends, HTTPException, status, File, UploadFile\n'), ((7217, 7237), 'fastapi.Depends', 'Depends', (['get_session'], {}), '(get_session)\n', (7224, 7237), False, 'from fastapi import APIRouter, Depends, HTTPException, status, File, UploadFile\n'), ((8042, 8062), 'fastapi.Depends', 'Depends', (['get_session'], {}), '(get_session)\n', (8049, 8062), False, 'from fastapi import APIRouter, Depends, HTTPException, status, File, UploadFile\n'), ((8170, 8190), 'fastapi.Depends', 'Depends', (['get_session'], {}), '(get_session)\n', (8177, 8190), False, 'from fastapi import APIRouter, Depends, HTTPException, status, File, UploadFile\n'), ((8298, 8318), 'fastapi.Depends', 'Depends', (['get_session'], {}), '(get_session)\n', (8305, 8318), False, 'from fastapi import APIRouter, Depends, HTTPException, status, File, UploadFile\n'), ((8428, 8448), 'fastapi.Depends', 'Depends', (['get_session'], {}), '(get_session)\n', (8435, 8448), False, 'from fastapi import APIRouter, Depends, HTTPException, status, File, UploadFile\n'), ((8549, 8569), 'fastapi.Depends', 'Depends', (['get_session'], {}), '(get_session)\n', (8556, 8569), False, 'from fastapi import APIRouter, Depends, HTTPException, status, File, UploadFile\n'), ((8676, 8696), 'fastapi.Depends', 'Depends', (['get_session'], {}), '(get_session)\n', (8683, 8696), False, 'from fastapi import APIRouter, Depends, HTTPException, status, File, UploadFile\n'), ((8800, 8820), 'fastapi.Depends', 'Depends', (['get_session'], {}), '(get_session)\n', (8807, 8820), False, 'from fastapi import APIRouter, Depends, HTTPException, status, File, UploadFile\n'), ((8937, 8957), 'fastapi.Depends', 'Depends', (['get_session'], {}), '(get_session)\n', (8944, 8957), False, 'from fastapi import APIRouter, Depends, HTTPException, status, File, UploadFile\n'), ((9077, 9097), 'fastapi.Depends', 'Depends', (['get_session'], {}), '(get_session)\n', (9084, 9097), False, 'from fastapi import APIRouter, Depends, HTTPException, status, File, UploadFile\n'), ((9195, 9215), 'fastapi.Depends', 'Depends', (['get_session'], {}), '(get_session)\n', (9202, 9215), False, 'from fastapi import APIRouter, Depends, HTTPException, status, File, UploadFile\n'), ((9310, 9330), 'fastapi.Depends', 'Depends', (['get_session'], {}), '(get_session)\n', (9317, 9330), False, 'from fastapi import APIRouter, Depends, HTTPException, status, File, UploadFile\n'), ((9436, 9456), 'fastapi.Depends', 'Depends', (['get_session'], {}), '(get_session)\n', (9443, 9456), False, 'from fastapi import APIRouter, Depends, HTTPException, status, File, UploadFile\n'), ((9565, 9585), 'fastapi.Depends', 'Depends', (['get_session'], {}), '(get_session)\n', (9572, 9585), False, 'from fastapi import APIRouter, Depends, HTTPException, status, File, UploadFile\n'), ((9697, 9717), 'fastapi.Depends', 'Depends', (['get_session'], {}), '(get_session)\n', (9704, 9717), False, 'from fastapi import APIRouter, Depends, HTTPException, status, File, UploadFile\n'), ((6884, 6939), 'fastapi.HTTPException', 'HTTPException', ([], {'status_code': '(404)', 'detail': '"""User not found"""'}), "(status_code=404, detail='User not found')\n", (6897, 6939), False, 'from fastapi import APIRouter, Depends, HTTPException, status, File, UploadFile\n'), ((7272, 7283), 'os.getcwd', 'os.getcwd', ([], {}), '()\n', (7281, 7283), False, 'import os\n'), ((6206, 6218), 'sqlalchemy.select', 'select', (['User'], {}), '(User)\n', (6212, 6218), False, 'from sqlalchemy import select\n'), ((6747, 6759), 'sqlalchemy.select', 'select', (['User'], {}), '(User)\n', (6753, 6759), False, 'from sqlalchemy import select\n'), ((7424, 7448), 'os.path.exists', 'os.path.exists', (['file_dir'], {}), '(file_dir)\n', (7438, 7448), False, 'import os\n'), ((7724, 7736), 'sqlalchemy.select', 'select', (['User'], {}), '(User)\n', (7730, 7736), False, 'from sqlalchemy import select\n'), ((5653, 5665), 'sqlalchemy.select', 'select', (['User'], {}), '(User)\n', (5659, 5665), False, 'from sqlalchemy import select\n'), ((5927, 5939), 'sqlalchemy.select', 'select', (['User'], {}), '(User)\n', (5933, 5939), False, 'from sqlalchemy import select\n'), ((7462, 7484), 'pathlib.Path', 'pathlib.Path', (['file_dir'], {}), '(file_dir)\n', (7474, 7484), False, 'import pathlib\n'), ((5306, 5318), 'sqlalchemy.select', 'select', (['User'], {}), '(User)\n', (5312, 5318), False, 'from sqlalchemy import select\n')]