from flask import Flask, jsonify, request, make_response
from flask_cors import CORS
from flask_bcrypt import Bcrypt
import uuid
from flask_jwt_extended import JWTManager, jwt_required, create_access_token, get_jwt, get_jwt_identity

# SQLalchemy
from sqlalchemy import create_engine
from flask_sqlalchemy import SQLAlchemy

import stripe
stripe.api_key = 'sk_test_51QtONkEDyKtJ4rtxadJjjtLZjg2N2c8OBnsackRarjLwOXSGXEi9TBTWeCGgLoqII0rQ2lzGZaA55JI7PfgL1Bww00ZITOFHNs'  # Tvoj Stripe secret key

import logging
import random
import string
from datetime import datetime
from datetime import timezone

import app_settings
import app_func
from app_getwork_models import TokenBlockList, Customer, Customer_data, Provider, Provider_data, Provider_service,Provider_reserved, Reviews, Payments, Orders

from dotenv import load_dotenv
load_dotenv('.env.testing')

app = Flask(__name__)
#CORS(app, origins=["http://localhost"], supports_credentials=True)
#app.url_map.strict_slashes = False  # prevents Flask's automatic redirect
#CORS(app, allow_headers=["Content-Type", "Authorization"])

# DB
engine = create_engine(app_settings.DB_URL, echo=True)
app.config['SQLALCHEMY_DATABASE_URI'] = app_settings.DB_URL
db = SQLAlchemy(app)
bcrypt = Bcrypt(app)

app.config['JWT_SECRET_KEY'] = app_settings.JWT_SECRET_KEY
app.config['JWT_ALGORITHM'] = 'HS256'
app.config["JWT_ACCESS_TOKEN_EXPIRES"] = app_settings.ACCESS_EXPIRES  #False=disable expiration
jwt = JWTManager(app)



@app.route('/debug', methods=['GET'])
def debug():
    return jsonify(dict(request.headers))

# Planet Routes
@app.route('/', methods=['GET'])
def index():
    app.logger.warning('API /main')
    return jsonify({"message":'Welcome to GetWork API v1.0!'}),200

@app.route('/hello', methods=['GET'])
def hello():
    app.logger.warning('API /hello')
    return jsonify({"message":'Hello GetWork API!'}),201

# Customer Register
#..................................................
@app.route('/register/customer', methods=['POST'])
def register_customer():
    app.logger.warning('API: register/customer INPUT')
    country_code ='+385' # TODO - input parameter
    res = {}
    try:
        data = request.get_json(force=True)
        mobile = data.get('mobile_phone')
        password = data.get('password')
    except Exception as e:
        res["error"] = str(e)
        app.logger.warning('API: register/customer DATA: ' + str(data))
        app.logger.warning('API: register/customer ERR_1: ' + str(e))
        return jsonify(res), 401
    # Check mobile number
    if (app_func.check_mobile(mobile)==False):
        res["error"] = "Incorrect mobile number"
        app.logger.warning('API: register/customer ERR_2: ' + res["error"])
        return jsonify(res), 409
    # Check if Customer is already registered
    check_mobile_row = db.session.query(Customer.mobile).filter_by(country_code=country_code, mobile=mobile).first()
    if check_mobile_row:
        # TODO - check if customer is inactive
        res["error"] = "That Customer already exists"
        app.logger.warning('API: register/customer ERR_3: ' + res["error"])
        return jsonify(res), 409
    else:
        new_uuid = uuid.uuid4()
        new_customer=Customer(new_uuid, country_code,mobile,password)
        db.session.add(new_customer)
        try:
            db.session.commit()
            # Add Customer data emtpy row
            db.session.refresh(new_customer)
            new_id = new_customer.id
            new_type = 4
            new_customer_data = Customer_data(
                customer_id=new_id,
                customer_type = new_type)
            db.session.add(new_customer_data)
            db.session.commit()
            res['message'] = "Customer added successfully"
            app.logger.warning('API: register/customer OUTPUT')
            return jsonify(res), 201
        except Exception as e:
            db.session.rollback()
            res["error"] = str(e)
            app.logger.warning('API: register/customer ERR_4: ' + res["error"])
            return jsonify(res), 500

# Customer Login
#..................................................
@app.route('/login/customer', methods=['POST'])
def login_customer():
    app.logger.warning('API: login/customer INPUT')
    res = {}
    try:
        data = request.get_json(force=True)
        #country_code = data.get('country_code')
        country_code = "+385"
        mobile = data.get('mobile_phone')
        password = data.get('password')
    except Exception as e:
        res["error"] = str(e)
        app.logger.warning('API: login/customer DATA:' + str(data))
        app.logger.warning('API: login/customer ERR_1: ' + str(e))
        return jsonify(res), 401

    customer_row = db.session.query(Customer.id,Customer.password).filter_by(country_code=country_code, mobile=mobile).first()
    if customer_row:
        check_password = bcrypt.check_password_hash(customer_row.password, password)
        if check_password:
            access_token = create_access_token(identity=str(customer_row.id))
            res['message'] = "Customer logged successfully"
            res["access_token"] = access_token
            app.logger.warning('API: login/customer OUTPUT ')
            return jsonify(res), 201
        else:
            res["error"] = "Wrong Username or Password"
            app.logger.warning('API: login/customer ERR_2: ' + res['error'])
            return jsonify(res), 401
    else:
        res["error"] = "Wrong Username or Password"
        app.logger.warning('API: login/customer ERR_3: ' + res["error"])
        return jsonify(res), 401

# Customer Get data
#..................................................
@app.route('/customer/getdata', methods=['GET'])
@jwt_required()
def customer_data():
    app.logger.warning('API: customer/getdata INPUT ')
    res = {}
    
    # Get Authorization header
    res = get_token(request)
    if 'error' in res:
        app.logger.warning('API: customer/getdata ERR_1: ' + res['error'])
        return jsonify(res), 401 
    customer_id = res['customer_id']
    
    # Find Customer data
    app.logger.warning('API: customer/getdata CUSTOMER_ID: ' + str(customer_id))
    customer_data_row = db.session.query(Customer_data).filter_by(customer_id=customer_id).one()
    db_json = app_func.class2json(customer_data_row)
    output_data = app_func.customer_output_data(db_json)
    # Get mobile
    customer_data_row = db.session.query(Customer).filter_by(id=customer_id).one()
    db_json = app_func.class2json(customer_data_row)
    value = db_json.get('mobile')
    output_data['mobile_phone'] = value
    
    res['message'] = "Customer get data succesfully"
    res["result"] = output_data
    app.logger.warning('API: customer/getdata OUTPUT')
    return jsonify(res),200

# Customer Add data
#..................................................
@app.route('/customer/adddata', methods=['POST'])
@jwt_required()
def customer_update():
    app.logger.warning('API: customer/adddata INPUT ')
    res = {}
    
    # Get Authorization header
    res = get_token(request)
    if 'error' in res:
        app.logger.warning('API: customer/adddata ERR_1: ' + res['error'])
        return jsonify(res), 401 
    customer_id = res['customer_id']
    
    # Get data
    address = None
    city = None
    email = None
    first_name = None
    last_name = None
    location = None
    language = None
    # Get data
    try:
        data = request.get_json(force=True)
        address = data.get('address')
        city = data.get('city')
        email = data.get('email')
        first_name = data.get('first_name')
        last_name = data.get('last_name')
        #location = data.get('location')
        # Set location from address
        location = str(app_func.set_location(address,city))
        language = 'HR'
    except Exception as e:
        res["error"] = str(e)
        app.logger.warning('API: customer/adddata DATA: ' + str(data))
        app.logger.warning('API: cutomer/adddata ERR_5: ' + str(e))
        return jsonify(res), 401
    
    # Find Customer data
    customer_data_row = db.session.query(Customer_data).filter_by(customer_id=customer_id).one()
    if customer_data_row:
        if address: customer_data_row.address = address
        if city: customer_data_row.city = city
        if email: customer_data_row.email = email
        if first_name: customer_data_row.first_name = first_name
        if last_name: customer_data_row.last_name = last_name
        if location: customer_data_row.location = location
        if language: customer_data_row.language = language
        try:
            db.session.commit()
        except Exception as e:
            db.session.rollback()
            res["error"] = str(e)
            app.logger.warning('API: customer/getdata ERR_6: ' + res['error'])
            return jsonify(res), 500
    
    res['message'] = "Update Successful"
    app.logger.warning('API: customer/adddata OUTPUT')
    return jsonify(res),200

# Customer Forget password
#..................................................
@app.route('/forget/customer', methods=['POST'])
def forget_customer():
    app.logger.warning('API: forget/customer INPUT')
    res = {}
    try:
        data = request.get_json(force=True)
        #country_code = data.get('country_code')
        country_code = "+385"
        mobile = data.get('mobile_phone')
        email = data.get('email')
    except Exception as e:
        res["error"] = str(e)
        app.logger.warning('API: forget/customer ERR_1: ' + str(e))
        return jsonify(res), 401

    customer_row = db.session.query(Customer).filter_by(country_code=country_code, mobile=mobile).first()
    if customer_row:
        app.logger.warning('API: forget/customer Customer-ID: ' + str(customer_row.id))
        # 1. Create new password:
        length = 6
        random_string = ''.join(random.choices(string.ascii_letters + string.digits, k=length))
        new_password = 'GetWork_' + random_string
        hashed_password = bcrypt.generate_password_hash(new_password).decode('utf-8')

        # 2. Send new password on email
        mail_sent = app_func.send_mail_password(email,new_password)
        if mail_sent:
            res['message'] = "Successful"
        else:
            res["error"] = "Email is not sent"
            app.logger.warning('API: forget/customer Email:' + str(email))
            app.logger.warning('API: forget/customer ERR_3: ' + res["error"])
            return jsonify(res), 401
        # 3. Update new password in DB
        customer_row.password = hashed_password
        try:
            db.session.commit()
            app.logger.warning('API: forget/customer DB: updated password' + str(hashed_password))
            app.logger.warning('API: forget/customer OUTPUT')
            return jsonify(res),200
        except Exception as e:
            db.session.rollback()
            res["error"] = str(e)
            app.logger.warning('API: forget/customer ERR_2: ' + res['error'])
            return jsonify(res), 500
    else:
        res["error"] = "Wrong Username"
        app.logger.warning('API: forget/customer ERR_4: ' + res["error"])
        return jsonify(res), 401
    
# Customer New password
#..................................................
@app.route('/newpassword/customer', methods=['POST'])
@jwt_required()
def newpassword_customer():
    app.logger.warning('API: newpassword/customer INPUT')
    res = {}
    
    # Get Authorization header
    res = get_token(request)
    if 'error' in res:
        app.logger.warning('API: newpassword/customer ERR_1: ' + res['error'])
        return jsonify(res), 401 
    customer_id = res['customer_id']
    
    # Get data
    try:
        data = request.get_json(force=True)
        old_password = data.get('password')
        new_password1 = data.get('new_password1')
        new_password2 = data.get('new_password2')
    except Exception as e:
        res["error"] = str(e)
        app.logger.warning('API: newpassword/customer DATA: ' + str(data))
        app.logger.warning('API: newpassword/customer ERR_5: ' + str(e))
        return jsonify(res), 401

    # Find Customer
    customer_row = db.session.query(Customer).filter_by(id=customer_id).one()
    if customer_row:
        check_password = bcrypt.check_password_hash(customer_row.password, old_password)
        if check_password:
            app.logger.warning('API: newpassword/customer OLD PASSWORD: OK')
        else:
            res["error"] = "Wrong Old Password"
            app.logger.warning('API: newpassword/customer ERR_6: ' + res['error'])
            return jsonify(res), 401
    else:
        res["error"] = "Wrong Username or Password"
        app.logger.warning('API: newpassword/customer ERR_7: ' + res["error"])
        return jsonify(res), 401
    
    # Set new password
    if new_password1 != new_password2:
        res["error"] = "New Passwords are not the same."
        app.logger.warning('API: newpassword/customer ERR_8: ' + res["error"])
        return jsonify(res), 401
    # Hash new password
    hashed_password = bcrypt.generate_password_hash(new_password1).decode('utf-8')
    # 3. Update new password in DB
    customer_row.password = hashed_password
    try:
        db.session.commit()
        app.logger.warning('API: newpassword/customer DB: updated password = ' + str(hashed_password))    
    except Exception as e:
        db.session.rollback()
        res["error"] = str(e)
        app.logger.warning('API: newpassword/customer ERR_9: ' + res['error'])
        return jsonify(res), 500
    
    res['message'] = "OK"
    app.logger.warning('API: newpassword/customer OUTPUT')
    return jsonify(res),200

# Customer Login check
#..................................................
@app.route('/logincheck/customer', methods=['GET'])
@jwt_required()
def logincheck_customer():
    app.logger.warning('API: logincheck/customer INPUT')
    res = {}
    res["loggedin"] = False
    # Get Authorization header
    res = get_token(request)
    if 'error' in res:
        app.logger.warning('API: logincheck/customer ERR_1: ' + res['error'])
        return jsonify(res), 401 
    #customer_id = res['customer_id']
    
    res["loggedin"] = True
    res["type"] = 'customer'
    app.logger.warning('API: logincheck/customer OUTPUT')
    return jsonify(res), 200

# Customer Logout
#..................................................
@app.route("/logout/customer", methods=["GET"])
@jwt_required()
def logout():
    app.logger.warning('API: logout/customer INPUT')
    res = {}
    res["loggedout"] = False
    auth_header = request.headers.get('Authorization')  # Get Authorization header
    if not auth_header:
        res["error"] = "Missing Authorization header"
        app.logger.warning('API: logout/customer ERR_1: ' + res['error'])
        return jsonify(res), 401

    jti = get_jwt()["jti"]
    customer_id = check_auth(auth_header,jti)
    now = datetime.now(timezone.utc)
    db.session.add(TokenBlockList(customer_id=customer_id,jti=jti, created_at=now))
    db.session.commit()
    res["loggedout"] = True
    res["type"] = 'customer'
    res['message'] = "Logged out successfully!"
    app.logger.warning('API: logout/customer OUTPUT')
    return jsonify(res), 200

#**************************************************
#   PROVIDER
# Provider list
#..................................................
@app.route('/provider/list', methods=['POST'])
@jwt_required()
def provider_list():
    app.logger.warning('API: provider/list INPUT')
    res = {}
    # Get Authorization header
    token = get_token(request)
    if 'error' in token:
        app.logger.warning('API: provider/list ERR_1: ' + token['error'])
        return jsonify(token), 401 
    customer_id = token['customer_id']
    # Customer location
    customer_data = db.session.query(Customer_data).filter_by(customer_id=customer_id).scalar()
 
    # Get data
    try:
        data = request.get_json(force=True)
        service_id = data.get('service')
    except Exception as e:
        res["error"] = str(e)
        app.logger.warning('API: provider/list DATA: ' + str(data))
        app.logger.warning('API: provider/list ERR_5: ' + str(e))
        return jsonify(res), 401

    # Provider list for service and city
    provider_list = (
    db.session.query(Provider_service)
    .join(Provider_data, Provider_service.provider_id == Provider_data.provider_id)
    .filter(
        Provider_service.service == service_id,
        Provider_service.price >= 0.0,
        Provider_data.city == customer_data.city
    ).all()
    )
    out_list = []
    for item in provider_list:
        out_json={}
        item_json = app_func.class2json(item) 
        # Delete any ID key
        item_json = app_func.deleteID(item_json)
        
        #Get provider uuid
        out_json['uuid'] = db.session.query(Provider.uuid).filter_by(id=item.provider_id).scalar()
        # Check provider location
        provider_data = db.session.query(Provider_data).filter_by(provider_id=item.provider_id).scalar()
        
        # Set output data
        out_json['provider_name'] = provider_data.first_name + " " + provider_data.last_name[0].upper() + "."
        # Calculate distance
        out_json['distance'] = app_settings.DISTANCE_MAX
        no_location = '{}'
        if customer_data.location !=no_location and provider_data.location !=no_location:
            out_json['distance'] = round(app_func.distance(customer_data.location,provider_data.location), 2)
        reviews_aver = item_json['reviews_aver']   
        app.logger.warning('API: provider/list TEST ' + reviews_aver)
        if reviews_aver == "None":
            reviews_aver = "-"
        
        out_json['review_aver'] = reviews_aver
        out_json['language'] = provider_data.language
        out_json['description_short'] = item_json['description_short'] 
        out_json['price'] = item_json['price']  
        out_list.append(out_json)
        
    # Distance sort 
    out_list = sorted(out_list, key=lambda x: x["distance"], reverse=False)
    for item in out_list:
        if item["distance"] == app_settings.DISTANCE_MAX:
            item["distance"] = "-"
    res['result'] = out_list
    service_json = {
        "id":int(service_id),
        "type":app_settings.service_type[int(service_id)]
    }
    res['service'] = service_json
    res['message'] = "OK"
    app.logger.warning('API: provider/list OUTPUT')
    return jsonify(res),200

# Provider details
#..................................................
@app.route('/provider/details', methods=['POST'])
@jwt_required()
def provider_details():
    app.logger.warning('API: provider/details INPUT')
    res = {}
    # Get Authorization header
    token = get_token(request)
    if 'error' in token:
        res["error"] = token['error']
        app.logger.warning('API: provider/details ERR_1: ' + token['error'])
        return jsonify(res), 401 
    customer_id = token['customer_id']
    
     # Get data
    try:
        data = request.get_json(force=True)
        provider_uuid = data.get('provider')
        service_id = data.get('service')
    except Exception as e:
        res["error"] = str(e)
        app.logger.warning('API: provider/details DATA: ' + str(data))
        app.logger.warning('API: provider/details ERR_2: ' + str(e))
        return jsonify(res), 401

    # Provider ID
    provider = db.session.query(Provider).filter_by(uuid=provider_uuid).scalar()
    if provider == None:
        res['error'] = "Wrong Provider uuid"
        app.logger.warning('API: provider/details DATA: ' + str(data))
        app.logger.warning('API: provider/details ERR_3: ' + res['error'])
        return jsonify(res), 401 
    
    provider_details = (
    db.session.query(Provider_service, Provider_data)
    .join(Provider_data, Provider_service.provider_id == Provider_data.provider_id)
    .filter(
        Provider_service.service == service_id,
        Provider_service.provider_id == provider.id
    ).all()
    )
    
    # Convert to list of dict(JSON-friendly)
    result_json = {}
    try:
        for service, data in provider_details:
            result_json = {
                "work_start": app_func.time_convert(service.work_start),
                "work_end": app_func.time_convert(service.work_end),
                "work_start1": service.work_start,
                "work_end1": service.work_end,
                "price":service.price,
                "currency":app_settings.currency['HR'],
                "vat": data.vat, #25.0,
                "review_aver":service.reviews_aver,
                "review_list":service.reviews,
                "service_description": service.description_short, 
                "provider_name": data.first_name,
                "provider_surname": data.last_name,
                "provider_language": data.language,
                "provider_description":data.description_long,
                "provider_calendar": set_calendar(provider.id,service_id),
                "uuid": provider.uuid
            }
    except Exception as e:
        res["error"] = str(e)
        app.logger.warning('API: provider/details DATA: ' + str(data))
        app.logger.warning('API: provider/details ERR_4: ' + str(e))
        return jsonify(res), 401
    
    # Output
    res['result'] = result_json
    
    res['message'] = "OK"
    app.logger.warning('API: provider/details OUTPUT')
    return jsonify(res),200

# Create payment
#..................................................
@app.route('/payment', methods=['POST'])
@jwt_required()
def payment():
    app.logger.warning('API: payment INPUT')
    res = {}
    res['payment'] = False
    
    # Get Authorization header
    token = get_token(request)
    if 'error' in token:
        res['error'] = token['error']
        app.logger.warning('API: payment ERR_1: ' + token['error'])
        return jsonify(res), 401 
    customer_id = token['customer_id']
    
     # Get data
    try:
        data = request.get_json(force=True)
        provider_uuid = data.get('provider')
        service_id = data.get('service')
        quantity = data.get('quantity')
        description = data.get('description')
        price = data.get('price')
        vat = data.get('vat')
        total_price = data.get('payment')
        currency = data.get('currency')
        service_date = data.get('service_date')
    except Exception as e:
        res["error"] = str(e)
        app.logger.warning('API: payment DATA: ' + str(data))
        app.logger.warning('API: payment ERR_2: ' + str(e))
        return jsonify(res), 401
    
    # Provider ID
    provider = db.session.query(Provider).filter_by(uuid=provider_uuid).scalar()
    if provider == None:
        res['error'] = "Wrong Provider uuid"
        app.logger.warning('API: payment DATA: ' + str(data))
        app.logger.warning('API: payment ERR_3: ' + res['error'])
        return jsonify(res), 401
    
    # Create Payment record
    app.logger.warning('API: payment DATA: ' + str(data))
    session_id = 0
    new_payment = Payments(provider.id, service_id, customer_id, service_date, quantity, price, total_price, currency, description)
    db.session.add(new_payment)
    try:
        db.session.commit()
        # Add Payment record
        db.session.refresh(new_payment)
        new_id = new_payment.id
        app.logger.warning('API: payment ***DETAILS***: ID: ' + str(new_id) + " Provider_ID: " + str(provider.id) + " Customer_ID: " + str(customer_id))
        app.logger.warning('API: payment - DB record: OK')
    except Exception as e:
        db.session.rollback()
        res["error"] = str(e)
        app.logger.warning('API: payment ERR_4: ' + res["error"])
        return jsonify(res), 500
    
    # Stripe session
    title = "GetWork usluga: " + str(app_func.service_convert(service_id)) + " (ID:" + str(service_id) + " #" + str(new_id) + "-" + str(provider.id) + "-" + str(customer_id) + ")"
    app.logger.warning('API: payment ***TITLE***: ' + str(title))
    stripe_price = round(float(total_price) * 100) 
    success_str = f'https://appgetwork.net/paid.html?result=True&id={new_id}'
    cancel_str = f'https://appgetwork.net/paid.html?result=False&id={new_id}'
    res['link'] = success_str
 
    try:
        if stripe_price > 0:
            session = stripe.checkout.Session.create(
                payment_method_types=['card'],
                mode='payment',
                line_items=[{
                    'price_data': {
                        'currency': currency,
                        'product_data': {
                            'name': title, # kreirati GetWork-service_id #payment_id-provider_id-customer_id
                        },
                        'unit_amount': stripe_price,  # in cents (10.00EUR = 1000 cents)
                    },
                    'quantity': 1,
                }],
                success_url = success_str, # status = True
                cancel_url = cancel_str, # status = False
            )
            session_id = session.id
            res['payment'] = True
            res['result'] = {'id': session_id}
        # Store session_id
        payment_i = db.session.query(Payments).filter_by(id=new_id).first()

        # Add title, session_id, status
        payment_i.title = title
        payment_i.session_id = session_id
        # Update record
        db.session.commit()
        
        # Add Review record (status = 1-> Paid)
        new_review = Reviews(new_id,payment_i.provider_id,payment_i.service,payment_i.customer_id,status=1)
        db.session.add(new_review)
        db.session.commit()
        db.session.refresh(new_review)
        new_id = new_review.id
        app.logger.warning('API: payment NEW Review record: ' + str(new_id))
        
    except Exception as e:
        res['error'] = str(e)
        app.logger.warning('API: payment ERR_5: ' + res["error"])
        return jsonify(error=str(e)), 500

    # Output
    res['message'] = "Payment ready!"
    app.logger.warning('API: payment OUTPUT')
    return jsonify(res),200

@app.route('/paid', methods=['POST'])
@jwt_required()
def paid():
    app.logger.warning('API: paid INPUT')
    res = {}
    
    # Get Authorization header
    token = get_token(request)
    if 'error' in token:
        res['error'] = token['error']
        app.logger.warning('API: payment ERR_1: ' + token['error'])
        return jsonify(res), 401 
    customer_id = token['customer_id']
    
    # Get data
    try:
        data = request.get_json(force=True)
        result = data.get('result') # True=paid; False=not paid
        id = data.get('id')
    except Exception as e:
        res["error"] = str(e)
        app.logger.warning('API: paid DATA: ' + str(data))
        app.logger.warning('API: paid ERR_2: ' + str(e))
        return jsonify(res), 401
    
    try:       
        # Find Payment ID
        payment_row = db.session.query(Payments).filter_by(id=id).one()
        if payment_row:
            result_stat = False
            if result == "True":
                result_stat = True           
            if payment_row.status != True:
                try:
                    payment_row.status = result_stat
                    db.session.commit()
                except Exception as e:
                    db.session.rollback()
                    res["error"] = str(e)
                    app.logger.warning('API: paid ERR_2: ' + res['error'])
                    return jsonify(res), 500
        
        # Get Provider data
        provider_id = payment_row.provider_id
        provider_data = db.session.query(Provider_data).filter_by(provider_id=provider_id).scalar()
        output_json = {}
        output_json['first_name'] = provider_data.first_name
        output_json['last_name'] = provider_data.last_name
        provider_login = db.session.query(Provider).filter_by(id=provider_id).scalar()
        
        if result=="True":
            mobile = app_func.set_mobile(provider_login.country_code,provider_login.mobile)  #"(" + str(provider_login.country_code) + ")" + provider_login.mobile
            output_json['mobile'] = mobile
            
        # Send payment notification (if mail_sent="")
        if len(payment_row.mail_sent) == 0:
            provider_email = provider_data.email
            payment_details = {}
            customer_id = payment_row.customer_id
            customer_data = db.session.query(Customer_data).filter_by(customer_id=customer_id).scalar()
            payment_details['service'] = app_settings.service_type[payment_row.service]
            payment_details['date'] = payment_row.date
            payment_details['quantity'] = payment_row.quantity
            payment_details['description'] = payment_row.description
            app.logger.warning('API: paid Customer Email:' + str(customer_data))
            provider_name = str(provider_data.first_name) + " " + str(provider_data.last_name)
            customer_name = str(customer_data.first_name) + " " + str(customer_data.last_name)
            
            # Send mail to Provider   
            payment_details['name_from'] = provider_name
            payment_details['name_to'] = customer_name
            mail_sent_txt = "00"
            mail_sent = app_func.send_mail_payment(provider_email,payment_details)
            if mail_sent:
                app.logger.warning('API: payment - Provider mail sent to:' + str(provider_email))
                mail_sent_txt = "1" + mail_sent_txt[1:]
            else:
                res["error"] = "Provider Email is not sent"
                app.logger.warning('API: paid Email:' + str(provider_email))
                app.logger.warning('API: paid ERR_3: ' + res["error"])
                #return jsonify(res), 401
            # Send mail to Customer
            customer_email = customer_data.email
            payment_details['name_from'] = customer_name
            payment_details['name_to'] = provider_name
            mail_sent = app_func.send_mail_payment(customer_email,payment_details)
            if mail_sent:
                app.logger.warning('API: payment - Customer mail sent to:' + str(customer_email))
                mail_sent_txt = mail_sent_txt[0] + "2"
            else:
                res["error"] = "Customer Email is not sent"
                app.logger.warning('API: paid Email:' + str(customer_email))
                app.logger.warning('API: paid ERR_4: ' + res["error"])

            # Update DB with mail_sent=True (if any email is sent)
            if mail_sent:
                if len(payment_row.mail_sent) == 0:
                    try:
                        payment_row.mail_sent = mail_sent_txt
                        db.session.commit()
                    except Exception as e:
                        db.session.rollback()
                        res["error"] = str(e)
                        app.logger.warning('API: paid ERR_5: ' + res['error'])
                        return jsonify(res), 500
                
        
    except Exception as e:
        res['error'] = str(e)
        app.logger.warning('API: paid ERR_6: ' + res["error"])
        return jsonify(error=str(e)), 500
    
    # Output
    res['message'] = "OK"
    res['result'] = output_json
    app.logger.warning('API: paid OUTPUT')
    return jsonify(res),200

@app.route('/paid/view', methods=['POST'])
@jwt_required()
def paid_view():
    app.logger.warning('API: paid/view INPUT')
    res = {}
    
    # Get Authorization header
    token = get_token(request)
    if 'error' in token:
        res['error'] = token['error']
        app.logger.warning('API: paid/view ERR_1: ' + token['error'])
        return jsonify(res), 401 
    customer_id = token['customer_id']
    
    # Get data
    try:
        data = request.get_json(force=True)
        #result = data.get('result') # True=paid; False=not paid or paid Preview
        id = data.get('id')
        app.logger.warning('API: paid/view DATA: ' + str(data))
    except Exception as e:
        res["error"] = str(e)
        app.logger.warning('API: paid/view DATA: ' + str(data))
        app.logger.warning('API: paid/view ERR_2: ' + str(e))
        return jsonify(res), 401
    
    try:       
        # Find Payment ID
        payment_row = db.session.query(Payments).filter_by(id=id).one()
        if payment_row:
            # Get Provider data
            provider_id = payment_row.provider_id
            provider_data = db.session.query(Provider_data).filter_by(provider_id=provider_id).scalar()
            output_json = {}
            output_json['first_name'] = provider_data.first_name
            output_json['last_name'] = provider_data.last_name
            
            provider_login = db.session.query(Provider).filter_by(id=provider_id).scalar()   
            mobile = app_func.set_mobile(provider_login.country_code,provider_login.mobile)
            output_json['mobile'] = mobile
            # Set service date
            output_json['service_date'] = payment_row.date
        
    except Exception as e:
        res['error'] = str(e)
        app.logger.warning('API: paid/view ERR_5: ' + res["error"])
        return jsonify(error=str(e)), 500
    
    # Output
    res['message'] = "OK"
    res['result'] = output_json
    app.logger.warning('API: paid/view OUTPUT')
    return jsonify(res),200

@app.route('/paid_list', methods=['POST'])
@jwt_required()
def paid_list():
    app.logger.warning('API: paid_list INPUT')
    res = {}
    
    # Get Authorization header
    token = get_token(request)
    if 'error' in token:
        res['error'] = token['error']
        app.logger.warning('API: paid_list ERR_1: ' + token['error'])
        return jsonify(res), 401 
    customer_id = token['customer_id']
        
    # Get all payments
    paid_all = []
    try:
        paid_list = db.session.query(Payments).filter_by(customer_id=customer_id, status=True).all()
        for payment in paid_list:
            paid_item = {}
            # Get Provier data
            provider_data = db.session.query(Provider_data).filter_by(provider_id=payment.provider_id).scalar()
            paid_item['payment_id'] = payment.id
            paid_item['provider_id'] = payment.provider_id
            paid_item['customer_id'] = payment.customer_id
            paid_item['provider_name'] = provider_data.first_name + " " + provider_data.last_name
            paid_item['service'] = app_settings.service_type[payment.service]
            paid_item['date'] = str(payment.date)
            paid_item['total_price'] = str(payment.total_price) + " " + str(payment.currency)
            paid_item['description'] = payment.description
            # Get Provider uuid
            provider = db.session.query(Provider).filter_by(id=payment.provider_id).one()
            paid_item['provider_uuid'] = provider.uuid
            # Check status
            review_row = db.session.query(Reviews).filter_by(payment_id=payment.id).scalar()
            status = app_settings.service_step[1]
            if review_row:
                paid_item['review'] = review_row.review_rate
                status = app_settings.service_step[review_row.status]
            paid_item['status'] = status
            paid_all.append(paid_item)
    except Exception as e:
        res["error"] = str(e)
        app.logger.warning('API: paid_list ERR_3: ' + str(e))
                   
    # Output
    res['message'] = "OK"
    res['result'] = paid_all
    app.logger.warning('API: paid_list OUTPUT')
    return jsonify(res),200

@app.route('/customer/review', methods=['POST'])
@jwt_required()
def customer_review():
    app.logger.warning('API: customer/review INPUT')
    res = {}
    
    # Get Authorization header
    token = get_token(request)
    if 'error' in token:
        res['error'] = token['error']
        app.logger.warning('API: customer/review ERR_1: ' + token['error'])
        return jsonify(res), 401 
    customer_id = token['customer_id']
    app.logger.warning('API: customer/review INPUT 2')
    
    # Get data
    try:
        data = request.get_json(force=True)
        review_type = data.get('review_type')
        payment_id = data.get('payment_id')
        review = data.get('review')
        comment = data.get('comment')
    except Exception as e:
        res["error"] = str(e)
        app.logger.warning('API: customer/review DATA: ' + str(data))
        app.logger.warning('API: customer/review ERR_2: ' + str(e))
        return jsonify(res), 401
    
    # Get review row
    review_row = db.session.query(Reviews).filter_by(payment_id=payment_id).one()
    if review_row:
        review_row.status = 3
        review_row.review_type = review_type
        review_row.comment = comment
        review_row.review_rate = review
        review_row.date_review = datetime.now(timezone.utc)
        try:
            db.session.commit()
        except Exception as e:
            db.session.rollback()
            res["error"] = str(e)
            app.logger.warning('API: customer/review ERR_3: ' + res['error'])
            return jsonify(res), 500
        app.logger.warning('API: customer/review ADD Review data ')
        
        # Add new review to Provider_service record
        provider_service = db.session.query(Provider_service).filter_by(
            provider_id=review_row.provider_id,
            service=review_row.service
        ).first()

        if provider_service:
            app.logger.warning('API: customer/review ADD Review ind1: ' + str(provider_service.reviews))
            provider_service_reviews = provider_service.reviews or []
            provider_service_reviews.append(review_row.id)
            app.logger.warning('API: customer/review ADD Review ind2: ' + str(provider_service_reviews))
            provider_service.reviews = provider_service_reviews
            db.session.commit()
            app.logger.warning('API: customer/review ADD Review ind3: ' + str(provider_service.reviews))

            # Calculate average rating
            provider_rates = db.session.query(Reviews.review_rate).filter_by(
                provider_id=review_row.provider_id,
                service=review_row.service,
                review_type=1
            ).all()
            ratings = [r[0] for r in provider_rates]
            provider_service_reviews_aver = sum(ratings) / len(ratings) if ratings else None
            provider_service.reviews_aver = round(provider_service_reviews_aver,2)
            db.session.commit()
        else:
            app.logger.warning('API: customer/review ERR4 - NO SERVICE')

    # Output
    res['message'] = "OK"
    app.logger.warning('API: customer/review OUTPUT')
    return jsonify(res),200

@app.route('/customer/order', methods=['POST'])
@jwt_required()
def customer_order():
    app.logger.warning('API: customer/order INPUT')
    res = {}
    
    # Get Authorization header
    token = get_token(request)
    if 'error' in token:
        res['error'] = token['error']
        app.logger.warning('API: customer/order ERR_1: ' + token['error'])
        return jsonify(res), 401 
    customer_id = token['customer_id']
    
    # Get data
    try:
        data = request.get_json(force=True)
        service_id = int(data.get('service'))
        date_time = data.get('date_time')
        comment = data.get('message')
    except Exception as e:
        res["error"] = str(e)
        app.logger.warning('API: customer/order DATA: ' + str(data))
        app.logger.warning('API: customer/order ERR_2: ' + str(e))
        return jsonify(res), 401
    
    new_order = Orders(service_id, customer_id, date_time, comment)
    db.session.add(new_order)
    try:
        db.session.commit()
        app.logger.warning('API: customer/order - DB record: OK')
    except Exception as e:
        db.session.rollback()
        res["error"] = str(e)
        app.logger.warning('API: customer/order ERR_4: ' + res["error"])
        return jsonify(res), 500
    
    # Send mail to GetWork   
    app.logger.warning('API: customer/order INPUT 2' + str(customer_id))
    customer_data = db.session.query(Customer_data).filter_by(customer_id=customer_id).scalar()
    order_details = {}
    app.logger.warning('API: customer/order INPUT 3 ' + str(service_id))
    order_details['service'] = app_settings.service_type[service_id]
    order_details['datetime'] = date_time
    order_details['description'] = comment
    customer_name = str(customer_data.first_name) + " " + str(customer_data.last_name)
    order_details['name_from'] = customer_name
    order_details['name_to'] = "GetWork team"
    getwork_email = "appgetwork2025@gmail.com"
    app.logger.warning('API: customer/order INPUT 4')
    mail_sent = app_func.send_mail_order(getwork_email,order_details)
    if mail_sent:
        app.logger.warning('API: customer/order - GetWork mail sent to:' + str(getwork_email))
    else:
        res["error"] = "GetWork Email is not sent"
        app.logger.warning('API: customer/order Email:' + str(getwork_email))
        app.logger.warning('API: customer/order ERR_3: ' + res["error"])

    # Send mail to Customer
    
    customer_email = customer_data.email
    order_details['name_from'] = "GetWork team"
    order_details['name_to'] = customer_name
    mail_sent = app_func.send_mail_order(customer_email,order_details)
    if mail_sent:
        app.logger.warning('API: customer/order - Customer mail sent to:' + str(customer_email))
    else:
        res["error"] = "Customer Email is not sent"
        app.logger.warning('API: customer/order Email:' + str(customer_email))
        app.logger.warning('API: customer/order ERR_4: ' + res["error"])

    # Output
    res['message'] = "OK"
    app.logger.warning('API: customer/order OUTPUT')
    return jsonify(res),200


# Authorization        
#----------------------------------------------------------------------------------
# Callback function to check if a JWT exists in the database blocklist
#@jwt.token_in_blocklist_loader
def check_if_token_revoked(jti) -> bool:
    #jti = get_jwt()["jti"]
    check_token_row = db.session.query(TokenBlockList.id).filter_by(jti=jti).first()
    if check_token_row:
        return True
    return False

def check_auth(auth_header,jti):
    #auth_header = request.headers.get('Authorization')  # Get Authorization header
    if check_if_token_revoked(jti):
        return -1
    customer_id=None
    if not auth_header:
        #return {"error": "Missing Authorization header"}, 401
        return customer_id

    # Expected format: "Bearer <token>"
    token = auth_header.split(" ")[1] if "Bearer" in auth_header else None
    if not token:
        #return {"error": "Invalid token format"}, 401
        return customer_id
    
    # Decode JWT without verification (useful for debugging)
    data = get_jwt()
    customer_id = int(data['sub'])
    return customer_id


def get_token(request):
    out={}
    # Get Authorization header
    auth_header = request.headers.get('Authorization') or request.environ.get('HTTP_AUTHORIZATION')
    if not auth_header:
        out["error"] = "Missing Authorization header"
        #app.logger.warning('API: provider/list ERR_1: ' + res['error'])
        #return jsonify(res), 401 
        return out

    # Check if token is revoken
    jti = get_jwt()["jti"]
    customer_id = check_auth(auth_header,jti)
    if customer_id is None:
        out["error"] = "Missing Authorization header"
        #app.logger.warning('API: provider/list ERR_2: ' + res['error'])
        #return jsonify(res), 401
        return out
    elif customer_id == -1:
        out["error"] = "Token revoked"
        #app.logger.warning('API: provider/list ERR_3: ' + res['error'])
        #return jsonify(res), 401
        return out

    # Expected format: "Bearer <token>"
    token = auth_header.split(" ")[1] if "Bearer" in auth_header else None
    if not token:
        out["error"] = "Invalid token format"
        #app.logger.warning('API: provider/list ERR_4: ' + res['error'])
        #return jsonify(res), 401
        return out
    
    out['customer_id'] = customer_id
    return out

def check_token_OLD(token_get):
    out = {}
    if not token_get:
        out["error"] = "Token missing"
        return out

    try:
        token = token_get.split(" ")[1]
        decoded = jwt.decode(token, app_settings.JWT_SECRET_KEY, algorithms=["HS256"])
        out['result'] = decoded
        return out
    except jwt.ExpiredSignatureError:
        out["error"] = "Token expired"
        return out
    except jwt.InvalidTokenError:
        out['error'] = "Invalid token"
        return out


def set_calendar(provider_id,service_id):
    from datetime import date, timedelta
    import holidays
    app.logger.warning('API /set_calendar INPUT')
    """ data = request.get_json(force=True)
    provider_id = data.get('provider')
    service_id = data.get('service') """
    # Set day ranges
    today = date.today()
    today_range = [today + timedelta(days=i) for i in range(app_settings.DELAY_DAYS)] # Disable first 2 day (today+tomorrow)
    dates_raw = [today + timedelta(days=i) for i in range(app_settings.TOTAL_DAYS)]  # Range 15 days
    # Set provider availability
    # TODO - read reservations records
    provider_reservations =[]
    provider_reservations_row = db.session.query(Provider_reserved).filter_by(provider_id=provider_id).all()
    for item in provider_reservations_row:
        item_json = app_func.class2json(item)
        date_datetime = datetime.strptime(item_json['date'], "%Y-%m-%d").date()
        provider_reservations.append(date_datetime)
    
    # Holidays
    dates_year = {d.year for d in dates_raw}
    dates_holiday = holidays.CountryHoliday('HR', years=dates_year)
    #dates_holiday = [d.strftime("%Y-%m-%d") for d in dates_holiday]
    
    # Provider prices
    provider_data = db.session.query(Provider_service).filter_by(provider_id=provider_id, service=service_id).scalar()
    provider_price = provider_data.price
    price_holiday = provider_data.holidays
    price_saturday = provider_data.saturdays
    price_sunday = provider_data.sundays
    # Saturdays
    saturdays = [d for d in dates_raw if d.weekday() == 5]
    # Sundays
    sundays = [d for d in dates_raw if d.weekday() == 6]
    
    events = []
    for datum in dates_raw:
        if datum in today_range:
            events.append({
                "title": "Ne radi",
                "start": datum.strftime("%Y-%m-%d"), 
                "display": "background",
                "backgroundColor": "gray",  # Pozadina sive boje za zauzeti dan
                "borderColor": "gray"  # Obavezno postaviti border za konzistentnost
                })
        elif datum in provider_reservations:
             events.append({
                "title": "-",
                "start": datum.strftime("%Y-%m-%d"), 
                "display": "background",
                "backgroundColor": "gray",  # Pozadina sive boje za zauzeti dan
                "borderColor": "gray"  # Obavezno postaviti border za konzistentnost
                })
        elif datum in dates_holiday:
            if price_holiday >= 0:
                #day_price = round(provider_price * price_holiday,2)
                day_price = round(price_holiday,2)
                events.append({
                "title": day_price,
                "start": datum.strftime("%Y-%m-%d"),
                "display": "background",
                "backgroundColor": "green",  # Pozadina sive boje za zauzeti dan
                "borderColor": "green"  # Obavezno postaviti border za konzistentnost
                })
            else:
                events.append({
                "title": "Ne radi",
                "start": datum.strftime("%Y-%m-%d"),
                "display": "background",
                "backgroundColor": "gray",  # Pozadina sive boje za zauzeti dan
                "borderColor": "gray"  # Obavezno postaviti border za konzistentnost
                })
        elif datum in saturdays:
            if price_saturday >= 0:
                #day_price = round(provider_price * price_saturday,2)
                day_price = round(price_saturday,2)
                events.append({
                "title": day_price,
                "start": datum.strftime("%Y-%m-%d"), 
                "display": "background",
                "backgroundColor": "green",  # Pozadina sive boje za zauzeti dan
                "borderColor": "green"  # Obavezno postaviti border za konzistentnost
                })
            else:
                events.append({
                "title": "Ne radi",
                "start": datum.strftime("%Y-%m-%d"), 
                "display": "background",
                "backgroundColor": "gray",  # Pozadina sive boje za zauzeti dan
                "borderColor": "gray"  # Obavezno postaviti border za konzistentnost
                })
        elif datum in sundays:
            if price_sunday >= 0:
                #day_price = round(provider_price * price_sunday,2)
                day_price = round(price_sunday,2)
                events.append({
                "title": day_price,
                "start": datum.strftime("%Y-%m-%d"),  
                "display": "background",
                "backgroundColor": "green",  # Pozadina sive boje za zauzeti dan
                "borderColor": "green"  # Obavezno postaviti border za konzistentnost
                })
            else:
                events.append({
                "title": "Ne radi",
                "start": datum.strftime("%Y-%m-%d"), 
                "display": "background",
                "backgroundColor": "gray",  # Pozadina sive boje za zauzeti dan
                "borderColor": "gray"  # Obavezno postaviti border za konzistentnost
                })
        else: # Working day
            day_price = round(provider_price,2)
            events.append({
                "title": day_price,
                "start": datum.strftime("%Y-%m-%d"),  
                "display": "background",
                "backgroundColor": "green",  # Pozadina sive boje za zauzeti dan
                "borderColor": "green"  # Obavezno postaviti border za konzistentnost
                })

    #return jsonify(events)
    app.logger.warning('API /set_calendar OUTPUT')
    return events
       
# Calendar test END
#----------------------------------------------------------------------------------

app.debug = True

if app.debug:
    import logging
    from logging.handlers import RotatingFileHandler
    
    """ file_handler = logging.FileHandler(app_settings.log_path + "appgetwork.log")
    file_handler.setLevel(logging.WARNING)
    formatter = logging.Formatter('%(asctime)s %(levelname)s %(message)s')
    file_handler.setFormatter(formatter)
    app.logger.addHandler(file_handler) """
    
    # Putanja do log datoteke
    log_file_path = app_settings.log_path + "appgetwork.log"

    # Handler koji rotira log kada pređe 10 MB, bez čuvanja starih verzija (backupCount=0)
    file_handler = RotatingFileHandler(
        log_file_path,
        maxBytes = 100 * 1024, # * 1024,  # 1 MB
        backupCount=5  # 5 starih log fileova
    )

    file_handler.setLevel(logging.WARNING)
    formatter = logging.Formatter('%(asctime)s %(levelname)s %(message)s')
    file_handler.setFormatter(formatter)

    # Dodaj handler aplikaciji (pretpostavljam da koristiš Flask)
    app.logger.addHandler(file_handler)
    
if __name__ == '__main__':
    app.run(debug=True, port=5002)