import { db } from '../../index.js';
import { serializeCrate } from '../../serializers/crate.js';
import { pageParams } from '../../utils/handlers.js';
import { http } from '../../utils/openapi-http.js';
import { getSession } from '../../utils/session.js';

export default http.get('/api/v1/crates', ({ request, response }) => {
  let url = new URL(request.url);

  let { start, end } = pageParams(request);

  let crates = db.crate.findMany();

  if (url.searchParams.get('following') === '1') {
    let { user } = getSession();
    if (!user) {
      return response('4XX').json(
        { errors: [{ detail: 'must be logged in to perform that action' }] },
        { status: 403 },
      );
    }

    crates = user.followedCrates;
  }

  let letter = url.searchParams.get('letter');
  if (letter) {
    letter = letter.toLowerCase();
    crates = crates.filter(crate => crate.name[0].toLowerCase() === letter);
  }

  let q = url.searchParams.get('q');
  if (q) {
    q = q.toLowerCase();
    crates = crates.filter(crate => crate.name.toLowerCase().includes(q!));
  }

  let userId = url.searchParams.get('user_id');
  if (userId) {
    let userIdNum = parseInt(userId, 10);
    crates = crates.filter(crate =>
      db.crateOwnership.findFirst(q =>
        q.where(ownership => ownership.crate.id === crate.id && ownership.user?.id === userIdNum),
      ),
    );
  }

  let teamId = url.searchParams.get('team_id');
  if (teamId) {
    let teamIdNum = parseInt(teamId, 10);
    crates = crates.filter(crate =>
      db.crateOwnership.findFirst(q =>
        q.where(ownership => ownership.crate.id === crate.id && ownership.team?.id === teamIdNum),
      ),
    );
  }

  let ids = url.searchParams.getAll('ids[]');
  if (ids.length !== 0) {
    crates = crates.filter(crate => ids.includes(crate.name));
  }

  let includeYanked = url.searchParams.get('include_yanked');
  if (includeYanked !== null && includeYanked !== 'yes') {
    crates = crates.filter(crate => {
      let versions = db.version.findMany(q => q.where({ crate: { id: crate.id } }));
      return versions.some(v => !v.yanked);
    });
  }

  let sort = url.searchParams.get('sort');
  if (sort === 'alpha') {
    crates = crates.toSorted((a, b) => compare(a.name.toLowerCase(), b.name.toLowerCase()));
  } else if (sort === 'recent-downloads') {
    crates = crates.toSorted((a, b) => b.recent_downloads - a.recent_downloads);
  }

  let total = crates.length;
  let serialized = crates
    .slice(start, end)
    .map(c => ({ ...serializeCrate(c), exact_match: c.name.toLowerCase() === q }));

  return response(200).json({ crates: serialized, meta: { total } });
});

export function compare(a: string, b: string) {
  return a < b ? -1 : a > b ? 1 : 0;
}
