from flask_restful import reqparse
from flask_cors import CORS
from sqlalchemy import create_engine, text
from sqlalchemy.exc import OperationalError
from flask_sqlalchemy import SQLAlchemy
from flask_bcrypt import Bcrypt
from flask_session import Session
from flask_login import LoginManager
from dotenv import load_dotenv

import os
import sys
import redis

load_dotenv()

db = SQLAlchemy()
bcrypt = Bcrypt()
login_manager = LoginManager()

GOOGLE_CLIENT_ID = os.getenv('GOOGLE_CLIENT_ID','None')
GOOGLE_CLIENT_SECRET = os.getenv('GOOGLE_CLIENT_SECRET','None')
GOOGLE_REDIRECT_URI = os.getenv('CURRENT_URL', 'http://localhost:5000') + '/api/access/google'
GOOGLE_RETURN_FRONTEND = os.getenv('GOOGLE_RETURN_FRONTEND','http://localhost:3000')

def anyaccess_initcall():
  return True

class AnyInit:
  SESSION_VERSION = os.getenv('GLOBAL_SESSION_VERSION', "1")

  @staticmethod
  def initCORS(app):
    origins_raw = os.getenv("ALLOWED_ORIGINS", "")
    origins = [origin.strip() for origin in origins_raw.split(",") if origin]
    
    if not origins:
      origins = ["http://localhost:3000"]
    
    CORS(
      app, 
      resources={r"/api/*": {"origins": origins}}, 
      supports_credentials=True
    )

    print(f"ANYFLASK LOG: CORS initialized for origins: {origins}")

  @staticmethod
  def initMariaDB(app):
    MARIA_URI = os.getenv("MARIA_KEY")
    try:
      engine = create_engine(MARIA_URI, connect_args={'connect_timeout': 2})
      with engine.connect() as conn:
        conn.execute(text("SELECT 1"))
      print(f"ANYFLASK LOG: Connected to MariaDB ---")
    except OperationalError as e:
      print(f"ANYFLASK ERR: MariaDB unreachable at {MARIA_URI}\nError: {e}", file=sys.stderr)
      sys.exit(1)
    except Exception as e:
      print(f"ANYFLASK ERR: Unexpected Database Error: {e}", file=sys.stderr)
      sys.exit(1)

    app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
    app.config['SQLALCHEMY_DATABASE_URI'] = MARIA_URI
    db.init_app(app)
    bcrypt.init_app(app)

  @staticmethod
  def initValkey(app):
    VALKEY_HOST = os.getenv("VALKEY_HOST", "host.containers.internal")
    valkey_client = redis.Redis(host=VALKEY_HOST, port=6379, db=0, socket_connect_timeout=2)
    try:
      valkey_client.ping()
      print(f"ANYFLASK LOG: Connected to Valkey")
    except Exception as e:
      print(f"ANYFLASK ERR: Valkey unreachable at {VALKEY_HOST}\nError: {e}", file=sys.stderr)
      sys.exit(1)
        
    app.config['SECRET_KEY'] = os.getenv('FLASK_SECRET_KEY', 'default-unsecure-key')
    app.config['SESSION_TYPE'] = 'redis'
    app.config['SESSION_REDIS'] = valkey_client
    app.config['SESSION_PERMANENT'] = False
    app.config['SESSION_USE_SIGNER'] = True
    app.config['SESSION_KEY_PREFIX'] = 'session:'

    Session(app)

  @staticmethod
  def initAPILogin(app):
    login_manager.init_app(app)


class MiniPresent:
  @staticmethod
  def status_act(status):
    match status:
      case 0: return "active"
      case 1: return "inactive"
      case _: return "unknown"
    

class Representation:
  @staticmethod
  def status_act(status):
    match status:
      case "active": return 0
      case "inactive": return 1
      case "_": return -1

  @staticmethod
  def status_check(user_check, args):
    old_status = user_check.status
    new_status = user_check.status
    if args.status is not None:
      if args.status not in ['active', 'inactive']:
        return old_status, new_status, True
      user_check.status = Representation.status_act(args.status)
      new_status = user_check.status
    return old_status, new_status, False

  @staticmethod
  def is_descending(ascend):
    ascend = ascend.lower()
    if ascend == 'ascending' or ascend == 'asce' or ascend == 'ascend':
      return False
    else:
      return True

  @staticmethod
  def Page_Details(page):
    page_details = {
      "has_prev":page.has_prev,
      "has_next":page.has_next,
      "prev_num":page.prev_num,
      "next_num":page.next_num,
      "current_page":page.page,
      "all_pages":page.pages,
      "per_page":page.per_page,
      "total":page.total
    }
    return page_details

  @staticmethod
  def Arguments(fields):
    dynamic_data = reqparse.RequestParser()
    for field in fields:
      if field.startswith('required:'):
        clean_name = field.replace('required:', '')
        dynamic_data.add_argument(
          clean_name, 
          required=True, 
          help=f"{clean_name} is required!"
        )
      else:
        dynamic_data.add_argument(field)
    return dynamic_data
  
  @staticmethod
  def GoogleArguments():
    dynamic_data = reqparse.RequestParser()
    dynamic_data.add_argument('code', location='args', required=True)
    return dynamic_data

  @staticmethod
  def ListArguments():
    dynamic_data = reqparse.RequestParser()
    fields = [ 'per_page' , 'current_page', 'order_by', 'sort_order', 'filter_type', 'filter_value', 'search', 'status']
    for field in fields:
      dynamic_data.add_argument(field, location='args')
    return dynamic_data

  @staticmethod
  def Message(message):
    try:
      parts = message.split(':', 1)
      status_number = int(parts[0])
      message_info = parts[1].strip() if len(parts) > 1 else ""  
      check_status = 'success' if status_number < 400 else 'fail'
      return {'status': check_status, 'message': message_info}, status_number
    except (ValueError, IndexError):
      return {'status': 'fail', 'message': 'Internal Server Error'}, 500

  def MessPage(message,page_details):
    return {'status':page_details,'message':message}, 200
