<?php
namespace controls;

class Users
{

  public static function permissions( $user_id, $module = '', $action = '' )
  {
    // Superadmin has full access
    if ( (int)$user_id === 1 )
      return true;

    // Cache permissions per user to avoid repeated DB queries
    static $cache = [];

    if ( !isset( $cache[ $user_id ] ) )
    {
      $repo = new \Domain\Users\PermissionRepository();
      $cache[ $user_id ] = $repo -> byUserId( (int)$user_id );
    }

    if ( $module === 'projects' )
    {
      $permissions = $cache[ $user_id ];

      if ( !$action )
        return isset( $permissions['projects_view'] ) ? (bool)$permissions['projects_view'] : true;

      if ( $action === 'project_delete' )
        return isset( $permissions['projects_delete'] ) ? (bool)$permissions['projects_delete'] : false;

      if ( $action === 'project_edit' || $action === 'project_save' )
      {
        $project_id = (int)\S::get( 'project_id' );
        $values = \S::json_to_array( \S::get( 'values' ) );
        if ( is_array( $values ) && isset( $values['id'] ) )
          $project_id = (int)$values['id'];

        if ( $project_id > 0 )
          return isset( $permissions['projects_edit'] ) ? (bool)$permissions['projects_edit'] : false;

        return isset( $permissions['projects_add'] ) ? (bool)$permissions['projects_add'] : false;
      }

      if ( strpos( $action, 'project_' ) === 0 )
        return isset( $permissions['projects_view'] ) ? (bool)$permissions['projects_view'] : false;

      return isset( $permissions['projects_view'] ) ? (bool)$permissions['projects_view'] : false;
    }

    if ( $module && isset( $cache[ $user_id ][ $module ] ) )
      return (bool)$cache[ $user_id ][ $module ];

    // If module not in permissions list, allow by default
    return true;
  }

  public static function logout()
  {
    global $mdb;

    $domain = preg_replace( '#^(http(s)?://)?w{3}\.#', '$1', $_SERVER['SERVER_NAME'] );
    $cookie_name = str_replace( '.', '-', $domain );
    $remember_token = $_COOKIE[$cookie_name] ?? '';

    if ( is_string( $remember_token ) && strlen( $remember_token ) === 64 && ctype_xdigit( $remember_token ) )
    {
      $mdb -> delete( 'users_remember_tokens', [ 'token_hash' => hash( 'sha256', $remember_token ) ] );
    }

    setcookie( $cookie_name, '', [
      'expires'  => strtotime( "-1 year" ),
      'path'     => '/',
      'domain'   => $domain,
      'secure'   => true,
      'httponly'  => true,
      'samesite'  => 'Lax'
    ] );
    session_destroy();
    header( 'Location: /' );
    exit;
  }


  public static function password_change()
  {
    global $mdb, $user;

    if ( !$user )
    {
      header( 'Location: /' );
      exit;
    }

    $password_old = \S::get( 'password_old' );
    $password_new = \S::get( 'password_new' );

    if ( !$password_old || !$password_new )
    {
      \S::alert( 'Wypełnij oba pola.' );
      header( 'Location: /users/settings/' );
      exit;
    }

    $db_user = $mdb -> get( 'users', '*', [ 'id' => $user['id'] ] );

    if ( !$db_user )
    {
      \S::alert( 'Stare hasło jest nieprawidłowe.' );
      header( 'Location: /users/settings/' );
      exit;
    }

    $password_ok = password_verify( $password_old, $db_user['password'] )
      || md5( $password_old ) === $db_user['password'];

    if ( !$password_ok )
    {
      \S::alert( 'Stare hasło jest nieprawidłowe.' );
      header( 'Location: /users/settings/' );
      exit;
    }

    $mdb -> update( 'users', [
      'password' => password_hash( $password_new, PASSWORD_BCRYPT )
    ], [
      'id' => $user['id']
    ] );

    \S::alert( 'Hasło zostało zmienione.' );
    header( 'Location: /users/settings/' );
    exit;
  }

  public static function settings()
  {
    global $user;

    if ( !$user )
    {
      return \Tpl::view( 'users/login-form' );
    }

    return \view\Users::settings(
        $user
    );
  }

  public static function login()
  {
    global $mdb;

    if ( $user = \factory\Users::login( \S::get( 'email' ), \S::get( 'password' ) ) )
    {
      $domain = preg_replace( '#^(http(s)?://)?w{3}\.#', '$1', $_SERVER['SERVER_NAME'] );
      $cookie_name = str_replace( '.', '-', $domain );
      $remember_token = $_COOKIE[$cookie_name] ?? '';

      $clear_remember_cookie = function() use ( $cookie_name, $domain )
      {
        setcookie( $cookie_name, '', [
          'expires'  => strtotime( '-1 year' ),
          'path'     => '/',
          'domain'   => $domain,
          'secure'   => true,
          'httponly'  => true,
          'samesite'  => 'Lax'
        ] );
      };
      $cleanup_remember_tokens = function() use ( $mdb )
      {
        $mdb -> query( 'DELETE FROM `users_remember_tokens` WHERE COALESCE(`last_used_at`, `created_at`) < DATE_SUB(NOW(), INTERVAL 6 MONTH)' );
      };
      $cleanup_remember_tokens();

      if ( is_string( $remember_token ) && strlen( $remember_token ) === 64 && ctype_xdigit( $remember_token ) )
      {
        $mdb -> delete( 'users_remember_tokens', [ 'token_hash' => hash( 'sha256', $remember_token ) ] );
      }

      if ( \S::get( 'remember' ) === 'true' )
      {
        $token = bin2hex( random_bytes( 32 ) );
        $mdb -> insert( 'users_remember_tokens', [
          'user_id'      => (int)$user['id'],
          'token_hash'   => hash( 'sha256', $token ),
          'created_at'   => date( 'Y-m-d H:i:s' ),
          'last_used_at' => date( 'Y-m-d H:i:s' ),
          'user_agent'   => substr( (string)($_SERVER['HTTP_USER_AGENT'] ?? ''), 0, 255 ),
          'ip'           => (string)($_SERVER['REMOTE_ADDR'] ?? '')
        ] );
        setcookie( $cookie_name, $token, [
          'expires'  => strtotime( "+1 year" ),
          'path'     => '/',
          'domain'   => $domain,
          'secure'   => true,
          'httponly'  => true,
          'samesite'  => 'Lax'
        ] );
      }
      else
      {
        $clear_remember_cookie();
      }

      \S::set_session( 'user', $user );
      echo json_encode( [ 'result' => 'true', 'msg' => 'Właśnie zostałeś zalogowany. Za chwilę nastąpi przekierowanie.', 'default_project' => $user[ 'default_project' ] ] );
    }
    else
    {
      echo json_encode( [ 'result' => 'false', 'msg' => 'Podany login i hasło są nieprawidłowe.' ] );
    }
    exit;
  }

  public static function login_form()
  {
    return \Tpl::view( 'users/login-form' );
  }

  /**
   * @deprecated Use \Controllers\UsersController::mainView() instead.
   */
  public static function main_view()
  {
    return \Controllers\UsersController::mainView();
  }

  /**
   * @deprecated Use \Controllers\UsersController::loginAs() instead.
   */
  public static function login_as()
  {
    return \Controllers\UsersController::loginAs();
  }

  /**
   * @deprecated Use \Controllers\UsersController::switchBackToAdmin() instead.
   */
  public static function back_to_admin()
  {
    return \Controllers\UsersController::switchBackToAdmin();
  }

}
