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 logging
import random
import string
from datetime import datetime
from datetime import timedelta
from datetime import timezone
from zoneinfo import ZoneInfo
import pytz

import app_settings
import app_func
import app_email
from app_models import TokenBlockList, Customer, Customer_data, Provider, Provider_data, Provider_service, Events, Reviews #Provider_reserved, Payments, Orders
from app_calendar import GoogleCalendarClient

import stripe

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"])
CORS(app, resources={r"/*": {"origins": "http://localhost:4200"}})

# 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)

#stripe.api_key = app_settings.STRIPE_KEY 


@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.info('API: register/customer INPUT')
    #country_code ='+385' # TODO - input parameter
    res = {}
    try:
        data = request.get_json(force=True)
        email = data.get('email')
        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 email
    if (app_func.check_email(email)==False):
        res["error"] = "Incorrect email"
        app.logger.warning('API: register/customer ERR_2: ' + res["error"])
        return jsonify(res), 409
    # Check if Customer is already registered
    check_email_row = db.session.query(Customer.email).filter_by(email=email).first()
    if check_email_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, email,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.info('API: register/customer NEW REGISTER: ' + str(email))
            # Send email to Fit&More
            to_email = app_settings.EMAIL_FROM
            subject = "New registration"
            html_content = "New Registration ID: " + str(new_id) + " email: " + str(email)

            #mail_sent = app_func.send_mail_register(getwork_email,register_details)
            ae = app_email.BrevoEmailService()
            mail_sent = ae.send(to_email,subject,html_content)

            if mail_sent:
                app.logger.info('API: register/customer - Registration mail sent - new ID: ' + str(new_id))
            else:
                res["error"] = "Registration Email is not sent"
                app.logger.warning('API: register/customer - Registration mail not sent - new ID: ' + str(new_id))
                app.logger.warning('API: register/customer ERR_4: ' + res["error"])
          
            app.logger.info('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_5: ' + res["error"])
            return jsonify(res), 500

# Customer Login
#..................................................
@app.route('/login/customer', methods=['POST'])
def login_customer():
    app.logger.info('API: login/customer INPUT')
    res = {}
    try:
        data = request.get_json(force=True)
        #country_code = data.get('country_code')
        #country_code = "+385"
        email = data.get('email')
        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(email=email).first()
    try:
        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
                # TODO - check profile data
                # res['profile'] = True or False
                customer_data = db.session.query(Customer_data).filter_by(customer_id=customer_row.id).first()
                res['profile'] = check_profile_data(customer_data)
                app.logger.info('API: login/customer PROFILE DATA: ' + str(res['profile']))
                app.logger.info('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
    except Exception as e:
        res["error"] = str(e)
        app.logger.warning('API: login/customer ERR_4: ' + str(e))
        return jsonify(res), 401

# Customer Get data
#..................................................
@app.route('/customer/getdata', methods=['GET'])
@jwt_required()
def customer_data():
    app.logger.info('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.info('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 email
    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('email')
    output_data['email'] = value
    
    res['message'] = "Customer get data succesfully"
    res["result"] = output_data
    app.logger.info('API: customer/getdata OUTPUT')
    return jsonify(res),200

# Customer Add data
#..................................................
@app.route('/customer/adddata', methods=['POST'])
@jwt_required()
def customer_update():
    app.logger.info('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
    mobile = 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')
        mobile = data.get('mobile')
        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 mobile: customer_data_row.mobile = mobile
        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.info('API: customer/adddata OUTPUT')
    return jsonify(res),200

# Customer Forget password
#..................................................
@app.route('/forget/customer', methods=['POST'])
def forget_customer():
    app.logger.info('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.info('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.info('API: forget/customer DB: updated password' + str(hashed_password))
            app.logger.info('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.info('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.info('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.info('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.info('API: newpassword/customer OUTPUT')
    return jsonify(res),200

# Customer Login check
#..................................................
@app.route('/logincheck/customer', methods=['GET'])
@jwt_required()
def logincheck_customer():
    app.logger.info('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.info('API: logincheck/customer OUTPUT')
    return jsonify(res), 200

# Customer Logout
#..................................................
@app.route("/logout/customer", methods=["GET", "POST"])
@jwt_required()
def logout():
    app.logger.info('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.info('API: logout/customer OUTPUT')
    return jsonify(res), 200


#*************************************************
#  CALENDAR
#-------------------------------------------------
# Customer Check Calendar for Reservation
#..................................................
@app.route('/customer/checkevents', methods=['POST'])
@jwt_required()
def customer_check_events():
    app.logger.info('API: customer/check_events INPUT ')
    res = {}
    res['error'] = False

    try:
        # Get Authorization header
        token = get_token(request)
        if 'error' in token:
            app.logger.warning('API: customer/check_calendar ERR_1: ' + token['error'])
            return jsonify(token), 401 
        
        # Get data
        try:
            data = request.get_json(force=True)
            service_id = int(data.get('serviceId'))
            #description = data.get('description')
        except Exception as e:
            res["error"] = str(e)
            app.logger.warning('API: customer/check_calendar DATA: ' + str(data))
            app.logger.warning('API: customer/check_calendar ERR_2: ' + str(e))
            return jsonify(res), 401
        
        #customer_id = res['customer_id']
        gc = GoogleCalendarClient(
            service_account_file=app_settings.SERVICE_ACCOUNT_FILE,
            calendar_id = app_settings.calendar_id[service_id] #.CALENDAR_ID
            )
        first_day = app_settings.DELAY_DAYS
        days_ahead = app_settings.TOTAL_DAYS
        
        ret = gc.get_events_in_range(service_id,first_day, days_ahead)
        if(ret['error']):
            res['error'] = ret['error']
            app.logger.warning('API: customer/check_events ERR_2: ' + res['error'])
            return res

        ####res['events'] = ret['events']
        arr = []
        for event in ret['events']:
            arr1={}
            arr1['start_time'] = app_func.time_calendar_convert(event['start']['dateTime'], event['start']['timeZone'])
            arr1['end_time'] = app_func.time_calendar_convert(event['end']['dateTime'], event['end']['timeZone'])
            arr.append(arr1)

    except Exception as e:
        res["error"] = str(e)
        app.logger.warning('API: customer/check_calendar DATA: ' + str(data))
        app.logger.warning('API: customer/check_events ERR_3: ' + str(e))
        return jsonify(res), 401
    
    res['events'] = arr
    res['service_time'] = app_settings.termin_duration_h[service_id]
    app.logger.info('API: customer/check_events OUTPUT ')
    # Ouptut datetiem format - dd.mm.yyyy HH:MM
    return res

# Customer add new event
#..................................................
@app.route('/customer/addevent', methods=['POST'])
@jwt_required()
def customer_add_event():
    app.logger.info('API: customer/add_event INPUT ')
    res = {}
    res['error'] = False

    try:
        # Get Authorization header
        token = get_token(request)
        if 'error' in token:
            app.logger.warning('API: customer/add_event ERR_1: ' + token['error'])
            return jsonify(token), 401 
        
        customer_id = token['customer_id']

        # Get data
        try:
            data = request.get_json(force=True)
            service_id = int(data.get('service_id'))
            #provider_id = int(data.get('provider_id'))
            start_time = data.get('start') # '2025-11-06T11:00:00.000Z'
            end_time = data.get('end') # '2025-11-06T11:00:00.000Z'
            description_inp = data.get('description')
        except Exception as e:
            res["error"] = str(e)
            app.logger.warning('API: customer/add_event DATA: ' + str(data))
            app.logger.warning('API: customer/add_event ERR_2: ' + str(e))
            return jsonify(res), 401
        
        gc = GoogleCalendarClient(
            service_account_file=app_settings.SERVICE_ACCOUNT_FILE,
            calendar_id = app_settings.calendar_id[service_id] #app_settings.CALENDAR_ID
            )
        tz = ZoneInfo(gc.timezone)
        # Add new event
        service_title = app_settings.service_type[service_id]
        summary = "Rezervacija " + str(service_title) + " - User #" + str(customer_id)
        location = app_settings.PRENOTED_TEXT
        
        # parsiranje ISO 8601 stringa u UTC
        start_time_utc = datetime.strptime(start_time, "%Y-%m-%dT%H:%M:%S.%fZ").replace(tzinfo=timezone.utc)
        end_time_utc = datetime.strptime(end_time, "%Y-%m-%dT%H:%M:%S.%fZ").replace(tzinfo=timezone.utc)

        # konverzija u lokalno vrijeme UTC+1
        start_time_local = start_time_utc.astimezone(tz)
        start_time_local_str = start_time_local.strftime("%Y-%m-%d %H:%M")

        # Timeslot is free -> create new event
        provider_id = 1 #TODO
        
        ret = gc.add_event(summary, start_time_local_str, service_id, description_inp, location)

        if (ret['error'] != False):
            res['error'] = ret['error']
            app.logger.warning('API: customer/add_event ERR_3: ' + str(res['error']))
            return jsonify(res), 401
        
        # Add new event in DB
        event_details = ret['event']
        datetime_start = event_details['start']

        # konverzija u format koji Google API očekuje
        datetime_end = {
            "dateTime": end_time_utc.strftime("%Y-%m-%dT%H:%M:%SZ"),
            "timeZone": event_details['end']['timeZone']
        }
        description = ""
        if 'description' in event_details:
            description = event_details['description']

        new_event = Events(service_id, provider_id, customer_id, event_details, datetime_start, datetime_end, description)
        db.session.add(new_event)
        try:
            db.session.commit()
            app.logger.info('API: customer/add_event - DB record: OK')
        except Exception as e:
            db.session.rollback()
            res["error"] = str(e)
            app.logger.warning('API: customer/add_event ERR_4: ' + res["error"])
            return jsonify(res), 500
    except Exception as e:
        res["error"] = str(e)
        app.logger.warning('API: customer/add_event ERR_5: ' + str(e))
        return jsonify(res), 401

    # Sending emails
    try:
        # Get customer email
        customer_row = db.session.query(Customer).filter_by(id=customer_id).one()
        customer_email = customer_row.email
        # Get provider email
        provider_id = 1 # TODO
        provider_row = db.session.query(Provider).filter_by(id=provider_id).one()
        provider_email = provider_row.email
        # Send email to Provider
        to_email = provider_email
        subject = "New event"
        html_content = "New Event ID: " + str(new_event.id) + " email: " + str(customer_email)

        ae = app_email.BrevoEmailService()
        mail_sent = ae.send(to_email,subject,html_content)

        if mail_sent:
            app.logger.info('API: customer/add_event - Event mail sent - new event ID: ' + str(new_event.id))
        else:
            res["error"] = "Event Email is not sent"
            app.logger.warning('API: customer/add_even - Event mail not sent to provider - new event ID: ' + str(new_event.id))
            app.logger.warning('API: customer/add_even ERR_6: ' + res["error"])

        # Send email to Customer
        to_email = customer_email
        subject = "Nova rezervacija"
        html_content = "Za potvrdu rezervacije kontaktirajte Fit&More na email: " + str(provider_email)

        ae = app_email.BrevoEmailService()
        mail_sent = ae.send(to_email,subject,html_content)

        if mail_sent:
            app.logger.info('API: customer/add_event - Event mail sent to Customer - new event ID: ' + str(new_event.id))
        else:
            res["error"] = "Event Email is not sent"
            app.logger.warning('API: customer/add_even - Event mail not sent - new event ID: ' + str(new_event.id))
            app.logger.warning('API: customer/add_even ERR_6: ' + res["error"])

    except Exception as e:
        res["error"] = str(e)
        app.logger.warning('API: customer/add_event-Email sending ERR_7: ' + str(e))
        return jsonify(res), 401    


    res['event'] = ret['event']
    app.logger.info('API: customer/add_event OUTPUT ')
    return res, 200

# Customer delete event
#..................................................
@app.route('/customer/deleteevent', methods=['POST'])
@jwt_required()
def customer_delete_event():
    app.logger.info('API: customer/delete_event INPUT ')
    res = {}
    res['error'] = False
    res['message'] = ""

    try:
        # Get Authorization header
        token = get_token(request)
        if 'error' in token:
            app.logger.warning('API: customer/delete_event ERR_1: ' + token['error'])
            return jsonify(token), 401 
        
        customer_id = token['customer_id']
        # Get data
        try:
            data = request.get_json(force=True)
            id = int(data.get('event_id')) # ID from DB
            app.logger.info('API: customer/delete_event DATA: ' + str(id))
        except Exception as e:
            res["error"] = str(e)
            app.logger.warning('API: customer/delete_event DATA: ' + str(data))
            app.logger.warning('API: customer/delete_event ERR_2: ' + str(e))
            return jsonify(res), 401
        
        # Read event data from DB
        event_data = db.session.query(Events).filter_by(id=id).scalar()
        if event_data:
            # Check Customer_id
            event_customer_id = event_data.customer_id
            if(event_customer_id != customer_id):
                res["error"] = "Customer ID is incorrect"
                app.logger.warning('API: customer/delete_event ERR_3: ' + res["error"])
                return jsonify(res), 401
            # Check event status
            status = event_data.status
            if(status != app_settings.PRENOTED_BY_USER):
                res["error"] = "Event can't be deleted"
                app.logger.warning('API: customer/delete_event ERR_4: ' + res["error"])
                return jsonify(res), 401
            event_details = event_data.event_details
            event_id = event_details['id']

            # Get service_id
            service_id = int(event_data.service_id)
            
            gc = GoogleCalendarClient(
                service_account_file=app_settings.SERVICE_ACCOUNT_FILE,
                calendar_id = app_settings.calendar_id[service_id] #app_settings.CALENDAR_ID
                )
            # Check on Prenoted text
            ret = gc.get_event_location(event_id)
            if(ret != app_settings.PRENOTED_TEXT):
                res["error"] = "Event can't be deleted - it is confirmed"
                app.logger.warning('API: customer/delete_event ERR_5: ' + res["error"])
                return jsonify(res), 401
            # Delete event in Calendar
            ret = gc.delete_event_by_id(event_id)
            if(ret['error']):
                res["error"] = ret['error']
                if "Resource has been deleted" not in res['error']:
                    app.logger.warning('API: customer/delete_event ERR_6: ' + res["error"])
                    return jsonify(res), 401
                app.logger.info('API: customer/delete_event: Event ' + str(id) + " is deleted from Google calendar!")
            
            app.logger.info('API: customer/delete_event: In Calendar Deleted Event ' + str(event_data.id))
            # Delete event in DB
            event_data.status = app_settings.DELETED_BY_USER
            try:
                db.session.commit()
                app.logger.info('API: customer/delete_event: In DB Deleted Event ' + str(event_data.id))
            except Exception as e:
                db.session.rollback()
                res["error"] = str(e)
                app.logger.warning('API: customer/delete_event ERR_7: ' + res['error'])
                return jsonify(res), 500
        else:
            res["error"] = "Event ID is incorrect"
            app.logger.warning('API: customer/delete_event ERR_8: ' + res["error"])
            return jsonify(res), 401
    except Exception as e:
        res["error"] = str(e)
        app.logger.warning('API: customer/delete_event ERR_9: ' + res["error"])
        return jsonify(res), 401

    res['message'] = "Event deleted"
    app.logger.info('API: customer/delete_event OUTPUT ')
    return res, 200

@app.route('/reservation_list', methods=['POST'])
@jwt_required()
def reservation_list():
    app.logger.info('API: reservation_list INPUT')
    res = {}
    
    # Get Authorization header
    token = get_token(request)
    if 'error' in token:
        res['error'] = token['error']
        app.logger.warning('API: reservation_list ERR_1: ' + token['error'])
        return jsonify(res), 401 
    customer_id = token['customer_id']
    app.logger.info('API: reservation_list USER: ' + str(customer_id))
    
    # Get all reservatyions
    try:
        reservations_list = db.session.query(Events).filter(Events.customer_id==customer_id, Events.status > 0).order_by(Events.id.desc()).all()
        reservations_list = [
            {
                "event_id": r.id,
                "provider_name": get_provider(r.provider_id),
                "provider_mobile": get_provider_mobile(r.provider_id),
                "service_id": r.service_id,
                "service": get_service(r.service_id),
                "datetime_start": get_localTime(r.datetime_start),
                "datetime_end": get_localTime(r.datetime_end),
                "date_init": r.date_init,
                "description": r.description,
                "valid_time_h": validation_calc(r.date_init,r.status),
                "status_id": r.status,
                "status": get_status(r.status),
                "review": get_review(r.id)
            }
            for r in reservations_list
        ]
    except Exception as e:
        res["error"] = str(e)
        app.logger.warning('API: reservation_list ERR_2: ' + str(e))
        return jsonify(res), 401
                   
    # Output
    res['message'] = "OK"
    res['result'] = reservations_list #paid_all
    app.logger.info('API: reservation_list OUTPUT')
    return jsonify(res),200
############################################################
############################################################

@app.route('/customer/review', methods=['POST'])
@jwt_required()
def customer_review():
    app.logger.info('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']
    
    # Get data
    try:
        data = request.get_json(force=True)
        event_id = int(data.get('event_id'))
        service_id = int(data.get('service_id'))
        review = float(data.get('review'))
        comment = str(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 Provider ID
    try:
        event_row = db.session.query(Events).filter_by(id=event_id).one()
        provider_id = event_row.provider_id
        if(event_row.customer_id != customer_id):
            res["error"] = "Customer ID is invalid"
            app.logger.warning('API: customer/review Customer ID: ' + str(customer_id))
            app.logger.warning('API: customer/review ERR_3: ' + res["error"])
            return jsonify(res), 401
        app.logger.info('API: customer/review Event ID: ' + str(event_id))
    except Exception as e:
        res["error"] = str(e)
        app.logger.warning('API: customer/review ERR_4: ' + res["error"])
        return jsonify(res), 401
    
    try:
        # Set Review datetime
        date_review = datetime.now(ZoneInfo("Europe/Zagreb"))
        
        # Add new review row
        new_review = Reviews(event_id, provider_id,service_id, customer_id, comment, review, date_review)
        db.session.add(new_review)
    except Exception as e:
        res["error"] = str(e)
        app.logger.warning('API: customer/review ERR_5: ' + res["error"])
        return jsonify(res), 401
       
    try:
        db.session.commit()
        app.logger.info('API: customer/review DB-Review record: OK')
    except Exception as e:
        db.session.rollback()
        res["error"] = str(e)
        app.logger.warning('API: customer/review ERR_6: ' + res["error"])
        return jsonify(res), 500
    
    # Set new event status
    event_row.status = 5
    # Spremanje promjena
    try:
        db.session.commit()
        app.logger.info('API: customer/review DB-Event record: OK')
    except Exception as e:
        db.session.rollback()
        res["error"] = str(e)
        app.logger.warning('API: customer/review ERR_7: ' + res["error"])
        return jsonify(res), 500

    # Output
    res['message'] = "OK"
    app.logger.info('API: customer/review OUTPUT')
    return jsonify(res),200


# Authorization        
#----------------------------------------------------------------------------------
# Callback function to check if a JWT exists in the database blocklist
def check_if_token_revoked(jti) -> bool:
    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):
    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"
        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"
        return out
    elif customer_id == -1:
        out["error"] = "Token revoked"
        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"
        return out
    
    out['customer_id'] = customer_id
    return out


#############################################################
# EVENT - CRON JOB
# ---------------------------------------------------
def check_events(req=None):
    # ako se poziva iz cron joba, req može biti None
    # 1. uzeti sve events sa status=1
    # 2. uzeti sve events koji su kreirani prije 24h (PRENOTED_PERIOD_H)
    # 3. za svaki stari event uzeti location text u Google calendaru
    # 4. Ako location text nije Prenoted (PRENOTED_TEXT) obrisati iz calendara i staviti status na -2 (DELETED_BY_APP)
    # 5. Poslati email customeru

    app.logger.info('CRON: check_events INPUT')
    
    # 1. trenutni datum i vrijeme
    #now = datetime.now()  # ili datetime.now() ako koristiš lokalno vrijeme
    now = datetime.now(timezone.utc)
    threshold = now - timedelta(hours=app_settings.PRENOTED_PERIOD_H)

    res = {}
    res['error'] = None
    try:
        customer_arr = []
        """ event_data = db.session.query(Events).filter_by(status=app_settings.PRENOTED_BY_USER).filter(
            Events.date_init < threshold).all() """
        event_data = db.session.query(Events).filter_by(status=app_settings.PRENOTED_BY_USER).all()
        
        for event in event_data:
            event_id = event.event_details['id']
            service_id = int(event.service_id)
            gc = GoogleCalendarClient(
                    service_account_file=app_settings.SERVICE_ACCOUNT_FILE,
                    calendar_id = app_settings.calendar_id[service_id] #app_settings.CALENDAR_ID
                    )         
            # Get location text
            location = gc.get_event_location(event_id)
            if(location == app_settings.PRENOTED_TEXT):
                if(event.date_init < threshold):
                    # Delete from Calendar and DB
                    ret = gc.delete_event_by_id(event_id)
                    if(ret['error']):
                        res['error'] = ret['error']
                        app.logger.warning('CRON: check_events ERR_1: ' + res['error'])
                        #return res
                    # Delete event in DB
                    event.status = app_settings.DELETED_BY_APP #DELETED_BY_USER
                    try:
                        db.session.commit()
                        res['message'] = "Deleted"
                        app.logger.info('CRON: check_events : Deleted event - ' + str(event.id))
                        #customer_arr.append(event.customer_id) # for mail sending
                    except Exception as e:
                        db.session.rollback()
                        res["error"] = str(e)
                        app.logger.warning('CRON: check_events ERR_2: ' + res['error'])
                        #return jsonify(res), 500  
                        return res
                    customer_row = db.session.query(Customer).filter_by(id=event.customer_id).one()
                    # TODO provider_row = db.session.query(Provider).filter_by(id=event.provider_id).one()
                    # Send email to Customer
                    #to_email = customer_row.email
                    to_emails = [customer_row.email, "mandul1111@gmail.com"]
                    subject = "Istek rezervacije"
                    html_content = "Vrijeme rezervacije (" + str(app_settings.PRENOTED_PERIOD_H) + ") je isteklo: " + str(event.datetime_start)
                    ae = app_email.BrevoEmailService()
                    mail_sent = ae.send(to_emails,subject,html_content)
                    if mail_sent:
                        app.logger.info('CRON: check_events - Delete Event mail sent to Customer - event ID: ' + str(event.id))
                    else:
                        res["error"] = "Delete Event Email is not sent"
                        app.logger.warning('CRON: check_events - Delete Event mail not sent - event ID: ' + str(event.id))
                        app.logger.warning('CRON: check_events ERR_3: ' + res["error"])

            elif(location.lower() == app_settings.ADMIN_DELETE_TEXT): # "obrisano"
                # Delete from Calendar and DB
                app.logger.info('CRON: check_events : ADMIN location text: ' + str(location))
                ret = gc.delete_event_by_id(event_id)
                if(ret['error']):
                    res['error'] = ret['error']
                    app.logger.warning('CRON: check_events ERR_4: ' + res['error'])
                    #return res
                # Delete event in DB
                event.status = app_settings.DELETED_BY_ADMIN #DELETED_BY_USER
                try:
                    db.session.commit()
                    res['message'] = "ADMIN Deleted"
                    app.logger.info('CRON: check_events : ADMIN Deleted event - ' + str(event.id))
                    customer_arr.append(event.customer_id) # for mail sending
                except Exception as e:
                    db.session.rollback()
                    res["error"] = str(e)
                    app.logger.warning('CRON: check_events ERR_5: ' + res['error'])
                    #return jsonify(res), 500  
                    return res
            elif(location.lower() == app_settings.ADMIN_DONE_TEXT):  # "done"
                # Update from Calendar and DB
                app.logger.info('CRON: check_events : ADMIN location text: ' + str(location))

                # Done event (status=3) in DB
                event.status = app_settings.DONE_BY_ADMIN # Izvršeno
                try:
                    db.session.commit()
                    res['message'] = "ADMIN Done"
                    app.logger.info('CRON: check_events : ADMIN Done event - ' + str(event.id))
                    #customer_arr.append(event.customer_id) # for mail sending
                except Exception as e:
                    db.session.rollback()
                    res["error"] = str(e)
                    app.logger.warning('CRON: check_events ERR_6: ' + res['error'])
                    #return jsonify(res), 500  
                    return res
            else:
                # Confirmed event
                event.status = app_settings.CONFIRMED_BY_ADMIN
                try:
                    db.session.commit()
                    res['message'] = "Confirmed"
                    app.logger.info('CRON: check_events ADMIN Confirmed - ' + str(event.id))
                except Exception as e:
                    db.session.rollback()
                    res["error"] = str(e)
                    app.logger.warning('CRON: check_events ERR_7: ' + res['error'])
                    #return jsonify(res), 500  
                    return res
    except Exception as e:
            res["error"] = str(e)
            app.logger.warning('CRON: check_events ERR_8: ' + res['error'])
            return res
    
    app.logger.info('CRON: check_events OUTPUT')
    return res

#############################################################
# INTERNAL FUNCTIONS
# ---------------------------------------------------
def check_profile_data(customer_row):
    valid_data = ['mobile', 'first_name']

    return all(
        getattr(customer_row, field) not in (None, '')
        for field in valid_data
    )

def validation_calc(datetime_init_db, status_db):
    # Ako nema timezone info, pretpostavi da je UTC
    if datetime_init_db.tzinfo is None:
        datetime_init_db = datetime_init_db.replace(tzinfo=timezone.utc)

    # Trenutno vrijeme u UTC
    now_utc = datetime.now(timezone.utc)

    # Izračun razlike
    diff = now_utc - datetime_init_db

    # Ukupno sekundi
    total_seconds = int(diff.total_seconds())

    # Sekundi u Prenoted period
    seconds_in_prenoted = app_settings.PRENOTED_PERIOD_H * 60 * 60  # 86400 sekundi
    remaining_seconds = seconds_in_prenoted - total_seconds

    # Pretvori u sate i minute
    hours = remaining_seconds // 3600
    minutes = (remaining_seconds % 3600) // 60

    # Provjeri da li je rezervacija istekla (negativna vrijenost)
    if (hours < 0):
        return "-"
    # Provjeri da li je rezervacija iotkazana (status=4)
    validation_time = [1]
    if (status_db not in validation_time):
        return "-"

    # Formatiraj kao hh:mm (npr. 02:45)
    hours_str = f"{hours:02d}:{minutes:02d}"
    return hours_str

def get_provider(provider_id):
    provider_id=int(provider_id)
    provider_data = db.session.query(Provider_data).filter_by(provider_id=provider_id).first()
    provider_name = provider_data.first_name + " " + provider_data.last_name
    return provider_name

def get_provider_mobile(provider_id):
    provider_id=int(provider_id)
    provider_data = db.session.query(Provider_data).filter_by(provider_id=provider_id).first()
    provider_mobile = provider_data.mobile
    return provider_mobile

def get_service(service_id):
    service_id=int(service_id)
    service = app_settings.service_type.get(service_id, "-") # Ako ID nije odredjen = "-"
    return service

def get_localTime(datetime_json):
    # 1. Učitaj UTC vrijeme iz stringa
    dt_utc = datetime.fromisoformat(datetime_json["dateTime"].replace("Z", "+00:00"))
    # Pretvori u lokalno vrijeme (iz JSON-a)
    local_tz = pytz.timezone(datetime_json["timeZone"])
    dt_local = dt_utc.astimezone(local_tz)
    # Formatiraj u string: dd-mm-yyyy HH:MM
    local_time = dt_local.strftime("%d-%m-%Y %H:%M")

    return local_time

def get_googleTime(datetime_json):
    # Google Calendar (i Google Calendar API) koristi RFC3339 format, tj. ISO-8601, primjerice: 2025-10-18T14:00:00+02:00
    # 1. Učitaj UTC vrijeme iz stringa
    dt_utc = datetime.fromisoformat(datetime_json["dateTime"].replace("Z", "+00:00"))

    # 2. Pretvori u lokalnu vremensku zonu
    tz = pytz.timezone(datetime_json["timeZone"])
    dt_local = dt_utc.astimezone(tz)

    # 3. Pretvori u Google Calendar format (RFC3339)
    google_time = dt_local.isoformat()  # primjer: '2025-10-18T16:00:00+02:00'

    return google_time

def get_status(status_id):
    status_id = int(status_id)
    status = app_settings.service_step.get(status_id, "-") # Ako ID nije odredjen = "-"
    return status

def get_description(event_json):
    desc = event_json.get("description", "")
    if desc:
        return desc
    else:
        return ""
    
def get_review(event_id):
    event_id = int(event_id)
    review_row = db.session.query(Reviews).filter_by(event_id=event_id).first()
    review_rate = 0
    if review_row:
        review_rate = review_row.review_rate
    return review_rate
       
# ##########################################################################
#----------------------------------------------------------------------------------

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 + "fitandmore.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.INFO)
    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)