from __future__ import annotations

from dataclasses import dataclass
from datetime import date, datetime
from io import BytesIO
from typing import Any

from fastapi import HTTPException
from openpyxl import Workbook, load_workbook
from sqlalchemy import select
from sqlalchemy.orm import Session

from app.core.security.passwords import hash_password
from app.modules.core.iam.models import User
from app.modules.core.iam.scope import validate_branch_matches_tenant
from app.modules.core.rbac.models import Role, UserRole
from app.modules.employees.models import (
    Employee,
    EmployeeLeaveBalance,
    EmployeeLeaveType,
    EmployeeSalaryStructure,
)
from app.modules.employees.service import EMPLOYEE_ROLE_NAMES, EMPLOYEE_STATUS, EMPLOYMENT_TYPES, EmployeeScope


IMPORT_TYPES = {
    "employees": "Employees / Staff",
    "leave_types": "Leave Types",
    "leave_balances": "Leave Balances",
    "salary_structures": "Salary Structures",
}

TEMPLATE_HEADERS: dict[str, list[str]] = {
    "employees": [
        "employee_code", "full_name", "email", "mobile", "alternate_mobile", "department", "designation",
        "employment_type", "date_of_joining", "status", "pan", "uan", "esi_no", "pf_no", "aadhaar_last4",
        "bank_name", "bank_account_no", "bank_ifsc", "address", "emergency_contact_name",
        "emergency_contact_mobile", "branch_id", "reporting_manager_email", "create_user", "login_email",
        "temporary_password", "employee_role", "notes",
    ],
    "leave_types": [
        "code", "name", "description", "annual_quota_days", "carry_forward_allowed", "allow_negative_balance",
        "requires_approval", "is_paid", "is_active", "branch_id",
    ],
    "leave_balances": [
        "employee_code", "leave_code", "opening_days", "credited_days", "availed_days", "adjusted_days", "balance_days", "branch_id",
    ],
    "salary_structures": [
        "employee_code", "effective_from", "effective_to", "pay_cycle", "monthly_ctc_amount", "basic_amount",
        "hra_amount", "allowance_amount", "employee_pf_amount", "employee_esi_amount", "professional_tax_amount",
        "tds_amount", "other_deduction_amount", "is_active", "remarks", "branch_id",
    ],
}

SAMPLE_ROWS: dict[str, list[Any]] = {
    "employees": [
        "EMP001", "Sample Staff", "staff@example.com", "9999999999", "", "Audit", "Associate",
        "full_time", "2026-04-01", "active", "ABCDE1234F", "", "", "", "1234", "Bank", "1234567890", "IFSC0000001",
        "Office address", "Emergency Contact", "9999999998", "", "", "no", "", "", "Staff", "Sample only - delete before import",
    ],
    "leave_types": ["CL", "Casual Leave", "Casual leave", 12, "yes", "no", "yes", "yes", "yes", ""],
    "leave_balances": ["EMP001", "CL", 0, 12, 0, 0, 12, ""],
    "salary_structures": ["EMP001", "2026-04-01", "", "monthly", 30000, 15000, 6000, 9000, 0, 0, 0, 0, 0, "yes", "Initial structure", ""],
}


@dataclass
class ImportRowResult:
    row_no: int
    status: str
    action: str
    data: dict[str, Any]
    messages: list[str]

    def as_dict(self) -> dict[str, Any]:
        return {"row_no": self.row_no, "status": self.status, "action": self.action, "data": self.data, "messages": self.messages}


def supported_import_types() -> dict[str, str]:
    return IMPORT_TYPES.copy()


def normalize_import_type(import_type: str) -> str:
    import_type = (import_type or "").strip().lower()
    if import_type not in IMPORT_TYPES:
        raise HTTPException(status_code=400, detail="Unsupported HR import type.")
    return import_type


def _safe_excel_sheet_title(title: str) -> str:
    """Return a valid Excel worksheet title for openpyxl."""
    invalid_chars = {"\\", "/", "?", "*", "[", "]", ":"}
    safe_title = "".join("-" if ch in invalid_chars else ch for ch in (title or "Sheet"))
    safe_title = safe_title.strip() or "Sheet"
    return safe_title[:31]


def build_template_workbook(import_type: str) -> bytes:
    import_type = normalize_import_type(import_type)
    wb = Workbook()
    ws = wb.active
    ws.title = _safe_excel_sheet_title(IMPORT_TYPES[import_type])
    headers = TEMPLATE_HEADERS[import_type]
    ws.append(headers)
    ws.append(SAMPLE_ROWS[import_type])
    for col_no, header in enumerate(headers, start=1):
        ws.cell(row=1, column=col_no).font = ws.cell(row=1, column=col_no).font.copy(bold=True)
        ws.column_dimensions[ws.cell(row=1, column=col_no).column_letter].width = max(14, min(28, len(header) + 4))
    bio = BytesIO()
    wb.save(bio)
    return bio.getvalue()


def parse_workbook_rows(content: bytes) -> list[dict[str, Any]]:
    try:
        wb = load_workbook(BytesIO(content), data_only=True)
    except Exception as exc:
        raise HTTPException(status_code=400, detail=f"Unable to read Excel file: {exc}")
    ws = wb.active
    raw_headers = [str(cell.value or "").strip().lower() for cell in ws[1]]
    headers = [h for h in raw_headers]
    if not any(headers):
        raise HTTPException(status_code=400, detail="Excel file has no header row.")
    rows: list[dict[str, Any]] = []
    for row_no, row in enumerate(ws.iter_rows(min_row=2, values_only=True), start=2):
        if not any(cell not in (None, "") for cell in row):
            continue
        item = {headers[idx]: _cell_value(row[idx] if idx < len(row) else None) for idx in range(len(headers)) if headers[idx]}
        item["_row_no"] = row_no
        rows.append(item)
    return rows


def preview_import(db: Session, scope: EmployeeScope, import_type: str, content: bytes) -> dict[str, Any]:
    import_type = normalize_import_type(import_type)
    rows = parse_workbook_rows(content)
    results: list[ImportRowResult] = []
    for row in rows:
        if import_type == "employees":
            results.append(_preview_employee(db, scope, row))
        elif import_type == "leave_types":
            results.append(_preview_leave_type(db, scope, row))
        elif import_type == "leave_balances":
            results.append(_preview_leave_balance(db, scope, row))
        elif import_type == "salary_structures":
            results.append(_preview_salary_structure(db, scope, row))
    valid = sum(1 for r in results if r.status == "valid")
    warning = sum(1 for r in results if r.status == "warning")
    error = sum(1 for r in results if r.status == "error")
    return {
        "import_type": import_type,
        "import_label": IMPORT_TYPES[import_type],
        "rows": [r.as_dict() for r in results],
        "summary": {"total": len(results), "valid": valid, "warning": warning, "error": error},
    }


def commit_import(db: Session, actor: User, scope: EmployeeScope, preview: dict[str, Any]) -> dict[str, Any]:
    import_type = normalize_import_type(preview.get("import_type"))
    created = updated = skipped = failed = 0
    errors: list[str] = []
    for row in preview.get("rows", []):
        if row.get("status") == "error":
            skipped += 1
            continue
        try:
            action = row.get("action") or "create"
            data = row.get("data") or {}
            if import_type == "employees":
                action = _commit_employee(db, actor, scope, data)
            elif import_type == "leave_types":
                action = _commit_leave_type(db, actor, scope, data)
            elif import_type == "leave_balances":
                action = _commit_leave_balance(db, actor, scope, data)
            elif import_type == "salary_structures":
                action = _commit_salary_structure(db, actor, scope, data)
            if action == "updated":
                updated += 1
            else:
                created += 1
        except Exception as exc:
            db.rollback()
            failed += 1
            errors.append(f"Row {row.get('row_no')}: {getattr(exc, 'detail', str(exc))}")
    return {"created": created, "updated": updated, "skipped": skipped, "failed": failed, "errors": errors}


def _cell_value(value: Any) -> Any:
    if isinstance(value, datetime):
        return value.date().isoformat()
    if isinstance(value, date):
        return value.isoformat()
    if isinstance(value, str):
        return value.strip()
    return value


def _blank(value: Any) -> Any:
    if value is None:
        return None
    if isinstance(value, str) and not value.strip():
        return None
    return value.strip() if isinstance(value, str) else value


def _str(value: Any, default: str = "") -> str:
    value = _blank(value)
    return str(value).strip() if value is not None else default


def _lower(value: Any, default: str = "") -> str:
    return _str(value, default).lower()


def _upper(value: Any, default: str = "") -> str:
    return _str(value, default).upper()


def _bool(value: Any, default: bool = False) -> bool:
    value = _blank(value)
    if value is None:
        return default
    if isinstance(value, bool):
        return value
    if isinstance(value, (int, float)):
        return bool(value)
    return str(value).strip().lower() in {"1", "true", "yes", "y", "on", "active"}


def _int(value: Any, default: int = 0) -> int:
    value = _blank(value)
    if value is None:
        return default
    try:
        return int(round(float(value)))
    except Exception:
        raise ValueError(f"Invalid integer/amount value: {value}")


def _date(value: Any) -> date | None:
    value = _blank(value)
    if not value:
        return None
    if isinstance(value, date):
        return value
    text = str(value).strip()
    for fmt in ("%Y-%m-%d", "%d-%m-%Y", "%d/%m/%Y", "%m/%d/%Y"):
        try:
            return datetime.strptime(text, fmt).date()
        except ValueError:
            pass
    return date.fromisoformat(text)


def _branch_id(scope: EmployeeScope, row: dict[str, Any]) -> int:
    raw = _blank(row.get("branch_id"))
    if raw is not None:
        branch_id = int(raw)
    elif scope.branch_id is not None:
        branch_id = int(scope.branch_id)
    else:
        raise ValueError("Branch is required. Select active branch or provide branch_id in Excel.")
    validate_branch_matches_tenant(_CURRENT_DB.get(), scope.tenant_id, branch_id)
    return branch_id


class _DbHolder:
    def __init__(self):
        self.db = None
    def set(self, db):
        self.db = db
    def get(self):
        return self.db

_CURRENT_DB = _DbHolder()


def _employee_by_code(db: Session, tenant_id: int, code: str) -> Employee | None:
    return db.execute(select(Employee).where(Employee.tenant_id == tenant_id, Employee.employee_code == code)).scalar_one_or_none()


def _leave_type_by_code(db: Session, tenant_id: int, branch_id: int, code: str) -> EmployeeLeaveType | None:
    return db.execute(select(EmployeeLeaveType).where(EmployeeLeaveType.tenant_id == tenant_id, EmployeeLeaveType.branch_id == branch_id, EmployeeLeaveType.code == code)).scalar_one_or_none()


def _preview_employee(db: Session, scope: EmployeeScope, row: dict[str, Any]) -> ImportRowResult:
    _CURRENT_DB.set(db)
    messages: list[str] = []
    data: dict[str, Any] = {"tenant_id": scope.tenant_id}
    try:
        data["branch_id"] = _branch_id(scope, row)
        data["employee_code"] = _upper(row.get("employee_code"))
        data["full_name"] = _str(row.get("full_name"))
        if not data["employee_code"] or not data["full_name"]:
            raise ValueError("employee_code and full_name are required.")
        data["email"] = _str(row.get("email")) or None
        data["mobile"] = _str(row.get("mobile")) or None
        data["alternate_mobile"] = _str(row.get("alternate_mobile")) or None
        data["department"] = _str(row.get("department")) or None
        data["designation"] = _str(row.get("designation")) or None
        data["employment_type"] = _lower(row.get("employment_type"), "full_time")
        if data["employment_type"] not in EMPLOYMENT_TYPES:
            raise ValueError(f"Invalid employment_type: {data['employment_type']}.")
        data["date_of_joining"] = _date(row.get("date_of_joining")).isoformat() if _date(row.get("date_of_joining")) else None
        data["status"] = _lower(row.get("status"), "active")
        if data["status"] not in EMPLOYEE_STATUS:
            raise ValueError(f"Invalid status: {data['status']}.")
        for key in ("pan", "uan", "esi_no", "pf_no", "aadhaar_last4", "bank_name", "bank_account_no", "bank_ifsc", "address", "emergency_contact_name", "emergency_contact_mobile", "notes"):
            data[key] = _str(row.get(key)) or None
        data["create_user"] = _bool(row.get("create_user"), False)
        data["login_email"] = (_str(row.get("login_email")) or data["email"] or "").lower() or None
        data["temporary_password"] = _str(row.get("temporary_password")) or None
        data["employee_role"] = _str(row.get("employee_role"), "Staff") or "Staff"
        mgr_email = _str(row.get("reporting_manager_email"))
        if mgr_email:
            mgr = db.execute(select(User).where(User.email == mgr_email.lower(), User.tenant_id == scope.tenant_id)).scalar_one_or_none()
            if not mgr:
                messages.append("Reporting manager email was not found; manager will be blank.")
            else:
                data["reporting_manager_user_id"] = mgr.id
        existing = _employee_by_code(db, scope.tenant_id, data["employee_code"])
        if existing and existing.branch_id != data["branch_id"]:
            raise ValueError("Employee code exists in another branch of this tenant.")
        if data["create_user"]:
            if not data["login_email"]:
                raise ValueError("login_email/email is required when create_user is yes.")
            if not existing and (not data["temporary_password"] or len(data["temporary_password"]) < 8):
                raise ValueError("temporary_password must be at least 8 characters when creating user.")
            if data["employee_role"] not in EMPLOYEE_ROLE_NAMES:
                messages.append("Invalid employee_role; Staff will be used.")
                data["employee_role"] = "Staff"
        return ImportRowResult(int(row.get("_row_no", 0)), "warning" if messages else "valid", "update" if existing else "create", data, messages)
    except Exception as exc:
        return ImportRowResult(int(row.get("_row_no", 0)), "error", "skip", data, [str(exc)])


def _preview_leave_type(db: Session, scope: EmployeeScope, row: dict[str, Any]) -> ImportRowResult:
    _CURRENT_DB.set(db)
    data: dict[str, Any] = {"tenant_id": scope.tenant_id}
    try:
        data["branch_id"] = _branch_id(scope, row)
        data["code"] = _upper(row.get("code"))
        data["name"] = _str(row.get("name"))
        if not data["code"] or not data["name"]:
            raise ValueError("code and name are required.")
        data["description"] = _str(row.get("description")) or None
        data["annual_quota_days"] = _int(row.get("annual_quota_days"), 0)
        data["carry_forward_allowed"] = _bool(row.get("carry_forward_allowed"), False)
        data["allow_negative_balance"] = _bool(row.get("allow_negative_balance"), False)
        data["requires_approval"] = _bool(row.get("requires_approval"), True)
        data["is_paid"] = _bool(row.get("is_paid"), True)
        data["is_active"] = _bool(row.get("is_active"), True)
        existing = _leave_type_by_code(db, scope.tenant_id, data["branch_id"], data["code"])
        return ImportRowResult(int(row.get("_row_no", 0)), "valid", "update" if existing else "create", data, [])
    except Exception as exc:
        return ImportRowResult(int(row.get("_row_no", 0)), "error", "skip", data, [str(exc)])


def _preview_leave_balance(db: Session, scope: EmployeeScope, row: dict[str, Any]) -> ImportRowResult:
    _CURRENT_DB.set(db)
    data: dict[str, Any] = {"tenant_id": scope.tenant_id}
    try:
        data["branch_id"] = _branch_id(scope, row)
        data["employee_code"] = _upper(row.get("employee_code"))
        data["leave_code"] = _upper(row.get("leave_code"))
        emp = _employee_by_code(db, scope.tenant_id, data["employee_code"])
        if not emp or emp.branch_id != data["branch_id"]:
            raise ValueError("Employee not found in selected/provided branch.")
        lt = _leave_type_by_code(db, scope.tenant_id, data["branch_id"], data["leave_code"])
        if not lt:
            raise ValueError("Leave type not found for selected/provided branch.")
        data["employee_id"] = emp.id
        data["leave_type_id"] = lt.id
        for key in ("opening_days", "credited_days", "availed_days", "adjusted_days"):
            data[key] = _int(row.get(key), 0)
        data["balance_days"] = _int(row.get("balance_days"), data["opening_days"] + data["credited_days"] + data["adjusted_days"] - data["availed_days"])
        existing = db.execute(select(EmployeeLeaveBalance).where(EmployeeLeaveBalance.tenant_id == scope.tenant_id, EmployeeLeaveBalance.employee_id == emp.id, EmployeeLeaveBalance.leave_type_id == lt.id)).scalar_one_or_none()
        return ImportRowResult(int(row.get("_row_no", 0)), "valid", "update" if existing else "create", data, [])
    except Exception as exc:
        return ImportRowResult(int(row.get("_row_no", 0)), "error", "skip", data, [str(exc)])


def _preview_salary_structure(db: Session, scope: EmployeeScope, row: dict[str, Any]) -> ImportRowResult:
    _CURRENT_DB.set(db)
    data: dict[str, Any] = {"tenant_id": scope.tenant_id}
    try:
        data["branch_id"] = _branch_id(scope, row)
        data["employee_code"] = _upper(row.get("employee_code"))
        emp = _employee_by_code(db, scope.tenant_id, data["employee_code"])
        if not emp or emp.branch_id != data["branch_id"]:
            raise ValueError("Employee not found in selected/provided branch.")
        data["employee_id"] = emp.id
        eff = _date(row.get("effective_from"))
        if not eff:
            raise ValueError("effective_from is required.")
        data["effective_from"] = eff.isoformat()
        eff_to = _date(row.get("effective_to"))
        data["effective_to"] = eff_to.isoformat() if eff_to else None
        if eff_to and eff_to < eff:
            raise ValueError("effective_to cannot be before effective_from.")
        data["pay_cycle"] = _lower(row.get("pay_cycle"), "monthly")
        for key in ("monthly_ctc_amount", "basic_amount", "hra_amount", "allowance_amount", "employee_pf_amount", "employee_esi_amount", "professional_tax_amount", "tds_amount", "other_deduction_amount"):
            data[key] = _int(row.get(key), 0)
        data["is_active"] = _bool(row.get("is_active"), True)
        data["remarks"] = _str(row.get("remarks")) or None
        existing = db.execute(select(EmployeeSalaryStructure).where(EmployeeSalaryStructure.tenant_id == scope.tenant_id, EmployeeSalaryStructure.employee_id == emp.id, EmployeeSalaryStructure.effective_from == eff)).scalar_one_or_none()
        return ImportRowResult(int(row.get("_row_no", 0)), "valid", "update" if existing else "create", data, [])
    except Exception as exc:
        return ImportRowResult(int(row.get("_row_no", 0)), "error", "skip", data, [str(exc)])


def _assign_role_if_needed(db: Session, user_id: int, role_name: str) -> None:
    role = db.execute(select(Role).where(Role.name == role_name, Role.is_active.is_(True))).scalar_one_or_none()
    if not role:
        return
    exists = db.execute(select(UserRole).where(UserRole.user_id == user_id, UserRole.role_id == role.id)).scalar_one_or_none()
    if not exists:
        db.add(UserRole(user_id=user_id, role_id=role.id))


def _get_or_create_user(db: Session, data: dict[str, Any], actor: User) -> int | None:
    if not data.get("create_user"):
        return None
    email = (data.get("login_email") or data.get("email") or "").lower().strip()
    if not email:
        return None
    existing = db.execute(select(User).where(User.email == email)).scalar_one_or_none()
    role_name = data.get("employee_role") or "Staff"
    if role_name not in EMPLOYEE_ROLE_NAMES:
        role_name = "Staff"
    if existing:
        _assign_role_if_needed(db, existing.id, role_name)
        return existing.id
    password = data.get("temporary_password") or ""
    if len(password) < 8:
        raise ValueError("temporary_password must be at least 8 characters.")
    user = User(
        email=email,
        full_name=data.get("full_name") or email,
        password_hash=hash_password(password),
        tenant_id=int(data["tenant_id"]),
        branch_id=int(data["branch_id"]),
        is_active=True,
        allow_login=True,
        is_locked=False,
        deleted_at=None,
        must_change_password=True,
        password_changed_at_utc=None,
    )
    db.add(user)
    db.flush()
    _assign_role_if_needed(db, user.id, role_name)
    return user.id


def _commit_employee(db: Session, actor: User, scope: EmployeeScope, data: dict[str, Any]) -> str:
    emp = _employee_by_code(db, scope.tenant_id, data["employee_code"])
    user_id = _get_or_create_user(db, data, actor)
    payload = dict(data)
    payload["date_of_joining"] = _date(payload.get("date_of_joining"))
    payload["is_active"] = payload.get("status") == "active"
    payload.pop("create_user", None)
    payload.pop("login_email", None)
    payload.pop("temporary_password", None)
    payload.pop("employee_role", None)
    payload.pop("employee_code", None)
    payload.pop("full_name", None)
    payload.pop("tenant_id", None)
    payload.pop("branch_id", None)
    if emp:
        emp.full_name = data["full_name"]
        emp.email = data.get("email")
        if user_id and not emp.user_id:
            emp.user_id = user_id
        for key, value in payload.items():
            if hasattr(emp, key):
                setattr(emp, key, value)
        emp.updated_by_user_id = actor.id
        emp.updated_at_utc = datetime.utcnow()
        db.commit()
        return "updated"
    emp = Employee(
        tenant_id=int(data["tenant_id"]), branch_id=int(data["branch_id"]), user_id=user_id,
        employee_code=data["employee_code"], full_name=data["full_name"], created_by_user_id=actor.id, updated_by_user_id=actor.id,
        **{k: v for k, v in payload.items() if hasattr(Employee, k)}
    )
    db.add(emp)
    db.commit()
    return "created"


def _commit_leave_type(db: Session, actor: User, scope: EmployeeScope, data: dict[str, Any]) -> str:
    row = _leave_type_by_code(db, scope.tenant_id, int(data["branch_id"]), data["code"])
    fields = ["name", "description", "annual_quota_days", "carry_forward_allowed", "allow_negative_balance", "requires_approval", "is_paid", "is_active"]
    if row:
        for field in fields:
            setattr(row, field, data.get(field))
        row.updated_by_user_id = actor.id
        row.updated_at_utc = datetime.utcnow()
        db.commit()
        return "updated"
    row = EmployeeLeaveType(tenant_id=scope.tenant_id, branch_id=int(data["branch_id"]), code=data["code"], created_by_user_id=actor.id, updated_by_user_id=actor.id, **{k: data.get(k) for k in fields})
    db.add(row)
    db.commit()
    return "created"


def _commit_leave_balance(db: Session, actor: User, scope: EmployeeScope, data: dict[str, Any]) -> str:
    row = db.execute(select(EmployeeLeaveBalance).where(EmployeeLeaveBalance.tenant_id == scope.tenant_id, EmployeeLeaveBalance.employee_id == data["employee_id"], EmployeeLeaveBalance.leave_type_id == data["leave_type_id"])).scalar_one_or_none()
    fields = ["opening_days", "credited_days", "availed_days", "adjusted_days", "balance_days"]
    if row:
        for field in fields:
            setattr(row, field, int(data.get(field) or 0))
        row.updated_by_user_id = actor.id
        row.updated_at_utc = datetime.utcnow()
        db.commit()
        return "updated"
    row = EmployeeLeaveBalance(tenant_id=scope.tenant_id, branch_id=int(data["branch_id"]), employee_id=int(data["employee_id"]), leave_type_id=int(data["leave_type_id"]), updated_by_user_id=actor.id, **{k: int(data.get(k) or 0) for k in fields})
    db.add(row)
    db.commit()
    return "created"


def _commit_salary_structure(db: Session, actor: User, scope: EmployeeScope, data: dict[str, Any]) -> str:
    effective_from = _date(data.get("effective_from"))
    row = db.execute(select(EmployeeSalaryStructure).where(EmployeeSalaryStructure.tenant_id == scope.tenant_id, EmployeeSalaryStructure.employee_id == data["employee_id"], EmployeeSalaryStructure.effective_from == effective_from)).scalar_one_or_none()
    payload = dict(data)
    payload["effective_from"] = effective_from
    payload["effective_to"] = _date(payload.get("effective_to"))
    for remove in ("employee_code", "tenant_id"):
        payload.pop(remove, None)
    fields = ["effective_from", "effective_to", "pay_cycle", "monthly_ctc_amount", "basic_amount", "hra_amount", "allowance_amount", "employee_pf_amount", "employee_esi_amount", "professional_tax_amount", "tds_amount", "other_deduction_amount", "is_active", "remarks"]
    if row:
        for field in fields:
            setattr(row, field, payload.get(field))
        row.updated_by_user_id = actor.id
        row.updated_at_utc = datetime.utcnow()
        db.commit()
        return "updated"
    row = EmployeeSalaryStructure(tenant_id=scope.tenant_id, branch_id=int(data["branch_id"]), employee_id=int(data["employee_id"]), created_by_user_id=actor.id, updated_by_user_id=actor.id, **{k: payload.get(k) for k in fields})
    db.add(row)
    db.commit()
    return "created"
