{ fetchFromGitLab
, pkgs
, lib
, stdenv
, makeWrapper
, python3
, poetry2nix
, nodejs-18_x
, ossOnly ? true
}:

let
  version = "1.16.0";
  suffix = lib.optionalString ossOnly "-oss";
  src' = fetchFromGitLab {
    owner = "baserow";
    repo = "baserow";
    rev = version;
    sha256 = "02ij94cqk5f0lsy8qiz0zrm9087swji9lxqbzy64jf1drqsdjj7a";
  };
  src = if ossOnly then pkgs.runCommand "${src'.name}${suffix}" {} ''
    cp -R ${src'} $out
    chmod -R u+w $out
    rm -rf $out/premium
    rm -rf $out/enterprise

    sed -i -e '/baserow_premium/d' -e '/baserow_enterprise/d' $out/backend/src/baserow/config/settings/base.py
    sed -i -e '/premium/d' -e '/enterprise/d' $out/web-frontend/config/nuxt.config.base.js
  '' else src';
  web-frontend-deps = import ./web-frontend {
    inherit pkgs nodejs;
    inherit (pkgs) system;
    src = "${src}/web-frontend";
  };

  nodejs = nodejs-18_x;
  poetry2nixOverrides = poetry2nix.defaultPoetryOverrides.overrideOverlay (self: super: let
    addBuildInputs = f: buildInputs: f.overridePythonAttrs (old: {
      buildInputs = (old.buildInputs or []) ++ buildInputs;
    });
  in {
    kombu = let
      kombuVersion = "5.2.4";
    in assert lib.assertMsg (super.kombu.version == kombuVersion) "kombu (${super.kombu.version}) is different version to what I expected (${kombuVersion}); maybe remove the override?"; super.kombu.overridePythonAttrs (old: {
      buildInputs = (old.buildInputs or []) ++ [ self.setuptools ];
      postPatch = ''
        ${old.postPatch or ""}
        substituteInPlace requirements/test.txt --replace "pytz>dev" "pytz"
      '';
    });
    opentelemetry-instrumentation-aiohttp = addBuildInputs super.opentelemetry-instrumentation-aiohttp [ self.hatchling ];
    opentelemetry-instrumentation-aiohttp-client = addBuildInputs super.opentelemetry-instrumentation-aiohttp-client [ self.hatchling ];
    opentelemetry-instrumentation-botocore = addBuildInputs super.opentelemetry-instrumentation-botocore [ self.hatchling ];
    opentelemetry-instrumentation-celery = addBuildInputs super.opentelemetry-instrumentation-celery [ self.hatchling ];
    opentelemetry-instrumentation-dbapi = addBuildInputs super.opentelemetry-instrumentation-dbapi [ self.hatchling ];
    opentelemetry-instrumentation-django = addBuildInputs super.opentelemetry-instrumentation-django [ self.hatchling ];
    opentelemetry-instrumentation-grpc = addBuildInputs super.opentelemetry-instrumentation-grpc [ self.hatchling ];
    opentelemetry-instrumentation-logging = addBuildInputs super.opentelemetry-instrumentation-logging [ self.hatchling ];
    opentelemetry-instrumentation-psycopg2 = addBuildInputs super.opentelemetry-instrumentation-psycopg2 [ self.hatchling ];
    opentelemetry-instrumentation-redis = addBuildInputs super.opentelemetry-instrumentation-redis [ self.hatchling ];
    opentelemetry-instrumentation-requests = addBuildInputs super.opentelemetry-instrumentation-requests [ self.hatchling ];
    opentelemetry-instrumentation-wsgi = addBuildInputs super.opentelemetry-instrumentation-wsgi [ self.hatchling ];
    django-health-check = addBuildInputs super.django-health-check [ self.sphinx self.setuptools-scm ];
    pysaml2 = addBuildInputs super.pysaml2 [ self.poetry-core ];
  });

  mkBackendSrc = { type, fromDir, pyproject, poetrylock, extra ? "" }: pkgs.runCommand "baserow-${type}-src" {
    inherit src pyproject poetrylock fromDir;
  } ''
    cp -r $src/$fromDir $out
    chmod -R +w $out

    cp $pyproject $out/pyproject.toml
    cp $poetrylock $out/poetry.lock
    cp $src/README.md $out
    rm $out/setup.py
    ${extra}
  '';
  mkBackendApp = {
    type, fromDir, pyproject, poetrylock, srcExtra ? "", postInstall ? ""
  }: let
    src = mkBackendSrc { inherit type fromDir pyproject poetrylock; extra = srcExtra; };
  in poetry2nix.mkPoetryApplication {
    projectDir = src;
    inherit pyproject poetrylock postInstall;
    overrides = poetry2nixOverrides;
    python = python3;
    passthru.src = src;
  };

  templates = pkgs.runCommand "baserow-templates" {
    inherit src;
  } ''
    cp -r "$src/backend/templates" $out
  '';
  backendApp = mkBackendApp {
    type = "backend";
    fromDir = "backend";
    pyproject = ./backend/pyproject.toml;
    poetrylock = ./backend/poetry.lock;
    srcExtra = ''
      substituteInPlace "$out/src/baserow/config/settings/base.py" \
        --replace 'APPLICATION_TEMPLATES_DIR = os.path.join(BASE_DIR, "../../../templates")' "APPLICATION_TEMPLATES_DIR = '${templates}'"
    '';
    postInstall = ''
      install -m 0755 ${./backend/gunicorn.py} $out/bin/baserow-gunicorn
      install -m 0755 ${./backend/celery.py} $out/bin/baserow-celery
    '';
  };
  premiumBackendApp = mkBackendApp {
    type = "premium-backend";
    fromDir = "premium/backend";
    pyproject = ./premium-backend/pyproject.toml;
    poetrylock = ./premium-backend/poetry.lock;
  };
  enterpriseBackendApp = mkBackendApp {
    type = "enterprise-backend";
    fromDir = "enterprise/backend";
    pyproject = ./enterprise-backend/pyproject.toml;
    poetrylock = ./enterprise-backend/poetry.lock;
  };
  backendEnv = backendApp.python.buildEnv.override (old: {
    extraLibs = [ backendApp ] ++ lib.optionals (!ossOnly) [ premiumBackendApp enterpriseBackendApp ];
  });
in
{
  inherit src web-frontend-deps;

  web-frontend = stdenv.mkDerivation {
    name = "baserow${suffix}-web-frontend";
    inherit src version;
    buildInputs = [ nodejs ];
    nativeBuildInputs = [ makeWrapper ];
    nodeDependencies = web-frontend-deps.shell.nodeDependencies;
    buildPhase = ''
      runHook preBuild

      outpath="$out/share/baserow"
      mkdir -p $outpath
      cp -R web-frontend $outpath/web-frontend

      ${lib.optionalString (!ossOnly) ''
        mkdir -p $outpath/premium
        cp -R premium/web-frontend $outpath/premium/web-frontend

        mkdir -p $outpath/enterprise
        cp -R enterprise/web-frontend $outpath/enterprise/web-frontend
      ''}

      # Disable prompts
      export MINIMAL=true
      export NODE_OPTIONS=--openssl-legacy-provider

      pushd $outpath/web-frontend
      mkdir node_modules
      for f in $nodeDependencies/lib/node_modules/*; do
        ln -s "$f" ./node_modules
      done
      export PATH="$nodeDependencies/bin:$PATH"
      ./node_modules/nuxt/bin/nuxt.js build --config-file config/nuxt.config.local.js
      popd

      mkdir $out/bin
      makeWrapper $nodeDependencies/lib/node_modules/nuxt/bin/nuxt.js $out/bin/baserow-web-frontend \
        --run "cd $outpath/web-frontend" \
        --add-flags "start --config-file config/nuxt.config.local.js"

      runHook postBuild
    '';
    dontInstall = true;
  };

  backend = backendEnv;
}