import { fetchSecurityConfig } from "../../utils/sysConfig";
import { checkDatabaseConfig } from "../../utils/middleware";
import { validateApiToken } from "../../utils/tokenValidator";
import { getDatabase } from "../../utils/databaseAdapter.js";

let securityConfig = {}
let basicUser = ""
let basicPass = ""

async function errorHandling(context) {
  try {
    return await context.next();
  } catch (err) {
    return new Response(`${err.message}\n${err.stack}`, { status: 500 });
  }
}

function basicAuthentication(request) {
  const Authorization = request.headers.get('Authorization');

  const [scheme, encoded] = Authorization.split(' ');

  // The Authorization header must start with Basic, followed by a space.
  if (!encoded || scheme !== 'Basic') {
    return BadRequestException('Malformed authorization header.');
  }

  // Decodes the base64 value and performs unicode normalization.
  // @see https://datatracker.ietf.org/doc/html/rfc7613#section-3.3.2 (and #section-4.2.2)
  // @see https://dev.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String/normalize
  const buffer = Uint8Array.from(atob(encoded), character => character.charCodeAt(0));
  const decoded = new TextDecoder().decode(buffer).normalize();

  // The username & password are split by the first colon.
  //=> example: "username:password"
  const index = decoded.indexOf(':');

  // The user & password are split by the first colon and MUST NOT contain control characters.
  // @see https://tools.ietf.org/html/rfc5234#appendix-B.1 (=> "CTL = %x00-1F / %x7F")
  if (index === -1 || /[\0-\x1F\x7F]/.test(decoded)) {
    return BadRequestException('Invalid authorization value.');
  }

  return {
    user: decoded.substring(0, index),
    pass: decoded.substring(index + 1),
  };
}

function UnauthorizedException(reason) {
  return new Response(reason, {
    status: 401,
    statusText: 'Unauthorized',
    headers: {
      'Content-Type': 'text/plain;charset=UTF-8',
      // Disables caching by default.
      'Cache-Control': 'no-store',
      // Returns the "Content-Length" header for HTTP HEAD requests.
      'Content-Length': reason.length,
    },
  });
}

function BadRequestException(reason) {
  return new Response(reason, {
    status: 400,
    statusText: 'Bad Request',
    headers: {
      'Content-Type': 'text/plain;charset=UTF-8',
      // Disables caching by default.
      'Cache-Control': 'no-store',
      // Returns the "Content-Length" header for HTTP HEAD requests.
      'Content-Length': reason.length,
    },
  });
}


/**
 * 根据请求路径提取所需权限
 * @param {string} pathname - 请求路径
 * @returns {string|null} 需要的权限类型或null
 */
function extractRequiredPermission(pathname) {
  // 提取路径中的关键部分
  const pathParts = pathname.toLowerCase().split('/');

  // 检查是否包含delete路径
  if (pathParts.includes('delete')) {
    return 'delete';
  }

  // 检查是否包含list路径
  if (pathParts.includes('list')) {
    return 'list';
  }

  // 其他情况返回null
  return null;
}

// CORS 跨域响应头
const corsHeaders = {
  'Access-Control-Allow-Origin': '*',
  'Access-Control-Allow-Methods': 'GET, POST, DELETE, PUT, OPTIONS',
  'Access-Control-Allow-Headers': 'Content-Type, Authorization',
  'Access-Control-Max-Age': '86400',
};

async function authentication(context) {
  // OPTIONS 预检请求不需要鉴权，直接返回 CORS 响应
  // 这是安全的，因为 OPTIONS 请求只是预检请求，不会执行任何实际操作
  if (context.request.method === 'OPTIONS') {
    return new Response(null, {
      status: 204,
      headers: corsHeaders
    });
  }

  // 读取安全配置
  securityConfig = await fetchSecurityConfig(context.env);
  basicUser = securityConfig.auth.admin.adminUsername
  basicPass = securityConfig.auth.admin.adminPassword

  if (typeof basicUser == "undefined" || basicUser == null || basicUser == "") {
    // 无需身份验证
    return context.next();
  } else {

    if (context.request.headers.has('Authorization')) {
      // 首先尝试使用API Token验证

      // 根据请求的 url 判断所需权限
      const pathname = new URL(context.request.url).pathname;
      const requiredPermission = extractRequiredPermission(pathname);

      const db = getDatabase(context.env);
      const tokenValidation = await validateApiToken(context.request, db, requiredPermission);
      if (tokenValidation.valid) {
        // Token验证通过，继续处理请求
        return context.next();
      }

      // 回退到使用传统身份认证方式
      const { user, pass } = basicAuthentication(context.request);
      if (basicUser !== user || basicPass !== pass) {
        return UnauthorizedException('Invalid credentials.');
      } else {
        return context.next();
      }

    } else {
      // 要求客户端进行基本认证
      return new Response('You need to login.', {
        status: 401,
        headers: {
          // Prompts the user for credentials.
          'WWW-Authenticate': 'Basic realm="my scope", charset="UTF-8"',
          // 'WWW-Authenticate': 'None',
        },
      });
    }

  }

}

export const onRequest = [checkDatabaseConfig, errorHandling, authentication];