def update(id: int):
    d = db.select(table="deliveries", conditions={"id": id}, multiple=False)
    if d is None:
        return jsonify(info="Delivery not found"), 404

    args = request.get_json(force=True)
    delivery = Delivery.parse(args, "update")
    if "errors" in delivery:
        return jsonify(errors=delivery["errors"]), 400
    delivery = delivery["delivery"]

    delivery["company_id"] = session["user"]["company_id"]

    # customer_id
    if "customer_id" in delivery:
        if not db.is_existing(table="customers", conditions={"id": delivery["customer_id"]}):
            return jsonify(info="Customer not found"), 404

        # sender_id
    if "sender_id" in delivery:
        if not db.is_existing(table="customers", conditions={"id": delivery["sender_id"]}):
            return jsonify(info="Sender not found"), 404

        # receiver_id
    if "receiver_id" in delivery:
        if not db.is_existing(table="customers", conditions={"id": delivery["receiver_id"]}):
            return jsonify(info="Receiver not found"), 404

    if "date_due" in delivery and d["driver_id"] is not None:
        db.delete(table="delivery_orders", conditions={"delivery_id": id})  # delete old date
        insert_at_last_order(id, delivery["date_due"], d["driver_id"])

    db.update(table="deliveries", params=delivery, conditions={"id": id})

    return jsonify(info="Delivery updated successfully"), 200
def create():
    company_id = session["user"]["company_id"]
    driver = request.get_json(force=True)
    driver = Driver.parse(driver, "create")
    
    if "errors" in driver:
        return jsonify(errors=driver["errors"]),400
    driver = driver["driver"]

    if db.is_existing(table="users",
                      conditions={"name": driver["name"], "type":"driver", "company_id":company_id}):
        return jsonify(info="Driver with the same name already exist"),400

    if db.is_existing(table="users",
                      conditions={"email": driver["email"], "type":"driver", "company_id": company_id}):
            return jsonify(info="Driver with the same email already exist"),400

    pwd = Generator.password()

    driver_data={
        "name" : driver["name"],
        "email" : driver["email"],
        "password" : generate_password_hash(pwd),
        "company_id" : company_id,
        "phone" : driver["phone"],
        "type":"driver"
    }
    driverId = db.insert(table="users", params=driver_data)
    return jsonify(info="Driver created successfully", driverId=driverId, password=pwd),200
def update(id:int):
    company_id = session["user"]["company_id"]
    if not db.is_existing(table="users", conditions={"id":id, "type":"driver", "company_id": company_id}):
        return jsonify(info="Driver not found"), 404

    driver = request.get_json(force=True)
    driver = Driver.parse(driver, "update")
    
    if "errors" in driver:
        return jsonify(errors=driver["errors"]),400
    driver = driver["driver"]
    driver_data = {}

    if "name" in driver:
        if db.is_existing(table="users",
                      conditions={"name": driver["name"], "type":"driver", "company_id": company_id}):
            return jsonify(info="Driver with the same name already exist"),400
        driver_data["name"] = driver["name"]

    if "email" in driver:
        if db.is_existing(table="users",
                      conditions={"email": driver["email"], "type":"driver", "company_id": company_id}):
            return jsonify(info="Driver with the same email already exist"),400
        driver_data["email"] = driver["email"]

    if "phone" in driver:
        driver_data["phone"] = driver["phone"]

    db.update(table="users", params=driver_data, conditions={"id": id})
    return jsonify(info="Driver updated successfully"),200
def set_vehicle(driver_id:int):

    def reset_vehicle(index, driver_id):
        _sql = """
                  UPDATE vehicles
                  SET vehicles.driver_id = NULL
                  WHERE vehicles.id = (
                    SELECT users.vehicle_id_""" + str(index) +"""
                    FROM users
                    WHERE users.id = %(id)s );
                """
        db.query(_sql, params={"id" : driver_id}, fetch=False)


    company_id = session["user"]["company_id"]
    if not db.is_existing(table="users",conditions={"id":driver_id, "type":"driver", "company_id": company_id}):
        return jsonify(info="Driver not found"), 404

    vehicles = request.get_json(force=True)
    vehicles = Driver.parse(vehicles, "set_vehicle")

    if "errors" in vehicles:
        return jsonify(errors=vehicles["errors"]),400

    vehicles = vehicles["vehicles"]

    for k,v in vehicles.items():

        if v is not None:

            if not db.is_existing(table="vehicles", conditions={"company_id": company_id, "id":v}):
                return jsonify(info="Vehicle " + str(k) + " not found"), 404

            _sql = """ SELECT 1 FROM vehicles WHERE company_id=%(company_id)s AND id= %(v_id)s AND (driver_id IS NULL OR driver_id=%(id)s); """

            # if wished vehicle is available
            if db.query(_sql,params={"company_id" : company_id, "id": driver_id, "v_id" : v}, multiple=False) is not None:

                # reset old vehicle
                reset_vehicle(k[1], driver_id)

                # update vehicle
                db.update(table="vehicles", params={"driver_id": driver_id}, conditions={"id":v})

            else :
                return jsonify(info="Vehicle " + str(k) + " already taken"), 400

        else :
            # reset old vehicle
            reset_vehicle(k[1], driver_id)

        # update user
        db.update(table="users", params={"vehicle_id_"+k[1]: v}, conditions={"id" : driver_id})

    return jsonify(info="Vehicles set successfully"), 200
def delete(id: int):
    company_id = session["user"]["company_id"]
    if not db.is_existing(table="vehicles", conditions={"id": id, "company_id": company_id}):
        return jsonify(info="Vehicle not found"), 404

    db.delete(table="vehicles", conditions={"id": id})
    return jsonify(info="Vehicle deleted successfully"), 200
def delete(id:int):
    company_id = session["user"]["company_id"]
    if not db.is_existing(table="users", conditions={"id":id, "type":"driver","company_id": company_id}):
        return jsonify(info="Driver not found"), 404

    db.delete(table="users", conditions={"id":id})
    return jsonify(info="Driver deleted successfully"),200
def delete(id:int):
    company_id = session["user"]["company_id"]
    existing_customer = db.is_existing(table="customers",conditions={"id": id, "company_id": company_id})
    if existing_customer is False:
        return jsonify(info="Customer not found"),404

    db.delete(table="customers", conditions={"id":id})
    return jsonify(info="Customer deleted successfully"),200
def get_signature(delivery_id):
    conditions = {"id": delivery_id, "company_id": session["user"]["company_id"]}
    if not db.is_existing(table="deliveries", conditions=conditions):
        return jsonify(info="Delivery not found"), 404

    file_path = os.path.join(app.config["UPLOAD_FOLDER"], delivery_id + ".png")
    if os.path.isfile(file_path):
        return send_file(file_path, "image/png")

    return jsonify(info="Signature not found"), 404
def upload_signature(delivery_id):
    conditions = {"id": delivery_id, "driver_id": session["user"]["id"], "company_id": session["user"]["company_id"]}
    if not db.is_existing(table="deliveries", conditions=conditions):
        return jsonify(info="Delivery not found"), 404

    if "file" in request.files:
        file = request.files["file"]
        if file.content_type == "image/png":
            file.save(os.path.join(app.config["UPLOAD_FOLDER"], delivery_id + ".png"))
            return jsonify(info="ok"), 200
        return jsonify(info="Content type must be 'image/png'"), 400
    abort(400)
def create():
    args = request.get_json(force=True)
    delivery = Delivery.parse(args, "create")
    if "errors" in delivery:
        return jsonify(errors=delivery["errors"]), 400

    delivery = delivery["delivery"]
    delivery["company_id"] = session["user"]["company_id"]

    if not db.is_existing(table="customers", conditions={"id": delivery["customer_id"]}):
        return jsonify(info="Customer not found"), 404

    # check existing customer
    if not db.is_existing(table="customers", conditions={"id": delivery["sender_id"]}):
        return jsonify(info="Sender not found"), 404

    # check existing customer
    if not db.is_existing(table="customers", conditions={"id": delivery["receiver_id"]}):
        return jsonify(info="Receiver not found"), 404

    delivery_id = db.insert(table="deliveries", params=delivery)

    return jsonify(info="Delivery created successfully", deliveryId=delivery_id), 200
def update(id: int):
    company_id = session["user"]["company_id"]

    if not db.is_existing(table="vehicles", conditions={"id": id, "company_id": company_id}):
        return jsonify(info="Vehicle not found"), 404

    rq = request.get_json(force=True)
    vehicle = Vehicle.parse(rq, "update")
    if "errors" in vehicle:
        return jsonify(errors=vehicle["errors"]), 400
    vehicle = vehicle["vehicle"]
    vehicle_data = {}

    if "registration" in vehicle:
        if db.is_existing(
            table="vehicles", conditions={"registration": vehicle["registration"], "company_id": company_id}
        ):
            return jsonify(info="Vehicle with the same registration already exist"), 400
        vehicle_data["registration"] = vehicle["registration"]

    if "type" in vehicle:
        vehicle_data["type"] = vehicle["type"]

    if "max_weight" in vehicle:
        max_weight = vehicle["max_weight"]
        if not (isinstance(max_weight, float) or isinstance(max_weight, int)) or max_weight > 100000 or max_weight < 0:
            abort(400)
        vehicle_data["max_weight"] = vehicle["max_weight"]

    if "max_area" in vehicle:
        max_area = vehicle["max_area"]
        if not (isinstance(max_area, float) or isinstance(max_area, int)) or max_area > 150 or max_area < 0:
            abort(400)
        vehicle_data["max_area"] = vehicle["max_area"]

    db.update(table="vehicles", params=vehicle_data, conditions={"id": id})
    return jsonify(info="Vehicle updated successfully"), 200
def update(id:int):
    company_id = session["user"]["company_id"]
    ### check existing customer
    if not db.is_existing(table="customers", conditions={"id":id, "company_id": company_id}):
        return jsonify(info="Customer not found"),404

    req = request.get_json(force=True)
    req = Customer.parse(req, "update")

    if "errors" in req:
        return jsonify(errors=req["errors"]),400
    req = req["customer"]
        
    customer = {}
    #name
    if "name" in req:
        if db.is_existing(table="customers", conditions={"name":req["name"],"company_id": company_id}):
            return jsonify(info="Customer with the same name already exists"),400

        customer["name"] = req["name"]

    #address
    if "address" in req:
        customer["address"] = req["address"]

    #location
    if "location" in req :
        customer["location_lat"] = req["location"]["lat"]
        customer["location_lng"] = req["location"]["lng"]

    #phone
    if "phone" in req:
        customer["phone"] = req["phone"]

    db.update(table="customers", params=customer, conditions={"id":id})
    return jsonify(info="Customer data updated successfully"),200
def create():
    company_id = session["user"]["company_id"]
    rq = request.get_json(force=True)
    vehicle = Vehicle.parse(rq, "create")
    if "errors" in vehicle:
        return jsonify(errors=vehicle["errors"]), 400
    vehicle = vehicle["vehicle"]

    if db.is_existing(table="vehicles", conditions={"registration": vehicle["registration"], "company_id": company_id}):
        return jsonify(info="Vehicle with the same registration already exist"), 400

    vehicle_data = {
        "registration": vehicle["registration"],
        "type": vehicle["type"],
        "max_weight": vehicle["max_weight"],
        "max_area": vehicle["max_area"],
        "company_id": company_id,
    }

    vehicle_id = db.insert(table="vehicles", params=vehicle_data)
    return jsonify(info="Vehicle created successfully", vehicleId=vehicle_id)
def assign_driver(delivery_id: int, driver_id: int):
    company_id = session["user"]["company_id"]
    if not db.is_existing(table="users", conditions={"id": driver_id, "type": "driver", "company_id": company_id}):
        return jsonify(info="Driver not found"), 404

    def get_valid_delivery(delivery_id, company_id):
        sql = "SELECT date_due FROM deliveries WHERE id=%(id)s AND company_id=%(company_id)s AND (state='not taken' OR state='not assigned');"
        return db.query(sql, params={"id": delivery_id, "company_id": company_id}, multiple=False)

    delivery = get_valid_delivery(delivery_id, company_id)
    if delivery is None:
        return jsonify(info="Delivery not found or not assignable"), 404

    db.update(
        table="deliveries",
        params={"driver_id": driver_id, "state": "not taken"},
        conditions={"id": delivery_id, "company_id": company_id},
    )

    insert_at_last_order(delivery_id, delivery["date_due"], driver_id)

    return jsonify(info="Driver has been assigned"), 200
def update_state():
    args = request.get_json(force=True)
    req = Delivery.parse(args, "update_state")
    if "errors" in req:
        return jsonify(errors=req["errors"]), 400

    state = req["state"]
    conditions = {"id": req["delivery_id"], "company_id": session["user"]["company_id"]}

    if session["user"]["type"] == "driver":
        conditions["driver_id"] = session["user"]["id"]

    delivery = db.is_existing(table="deliveries", conditions=conditions)

    if not delivery:
        return jsonify(info="Delivery not found"), 404

    if state == "canceled":
        db.update(table="deliveries", params={"canceled": 1}, conditions=conditions)
    else:
        db.update(table="deliveries", params={"state": state}, conditions=conditions)

    return jsonify(info="Delivery state has been updated"), 200
def create():
    req = request.get_json(force=True)
    customer = Customer.parse(req, "create")
    if "errors" in customer:
        return jsonify(errors=customer["errors"]),400
    customer = customer["customer"]

    ### check customer name duplication
    company_id = session["user"]["company_id"]
    if db.is_existing(table="customers",
                      conditions={"name":customer["name"], "company_id":company_id}):
        return jsonify(info="Customer with the same name already exist"),400

    # record customer
    data = {
        "name" : customer["name"],
        "address" : customer["address"],
        "location_lat" : customer["location"]["lat"],
        "location_lng" : customer["location"]["lng"],
        "phone" : customer["phone"],
        "company_id" : company_id
    }
    customerId= db.insert(table="customers", params=data)
    return jsonify(info="Customer created successfully", customerId=customerId),200
def delete(id: int):
    if not db.is_existing(table="deliveries", conditions={"id": id, "company_id": session["user"]["company_id"]}):
        return jsonify(info="Delivery not found"), 404

    db.delete(table="deliveries", conditions={"id": id})
    return jsonify(info="Delivery deleted successfully"), 200