import { exec } from "child_process"
import fs from "fs"

import gulp from "gulp"
import path from "path"
//import { argv } from 'yargs/yargs';
import { Transform } from "stream"
import { fileURLToPath } from "url"
import { handleTerminalOutput, getBuildFolderPath } from "../utils/paths.js"
import { BASE_PLUGIN_PATH } from "../constants/config.js"
import { getPlanFromCli } from "../utils/readCliParams.js"
import { plans } from "../constants/plans.js"
import { zipFilesTask } from "./zip.js"
import { getConfig } from "../constants/config.js"
import { readJSON, writeJSON } from "./bump.js"

const __filename = fileURLToPath(import.meta.url)
const __dirname = path.dirname(__filename)

// Function to replace features in PHP files
function replaceFeaturesPhpJs(content, featuresToRemove) {
  const regex =
    /(?:\/\/)\s*START\s+(\w+)([\s\S]*?)(?:\/\/\sREPLACE\s*?\S*?([\s\S]*?))?(?:\/\/)\s*END\s*?/g

  return content.replace(regex, (match, featureName, code, replace) => {
    if (featuresToRemove.includes(featureName)) {
      return replace ? replace.replace(/^\s*\/\/\s*/gm, "") : ""
    }
    return match
  })
}

// Function to replace features in HTML/Handlebars files
function replaceFeaturesHTML(content, featuresToRemove) {
  featuresToRemove.forEach((feature) => {
    const htmlRegex = new RegExp(
      `<!--\\s*START\\s*${feature}\\s*-->[\\s\\S]*?<!--\\s*END(?:\\s*REPLACE[\\s\\S]*?)?\\s*-->`,
      "g",
    )

    content = content.replace(htmlRegex, (match) => {
      const replaceMatch = match.match(/<!--\s*END\s*REPLACE([\s\S]*?)-->/)
      if (replaceMatch) {
        // Extract code between END REPLACE and -->
        return replaceMatch[1].trim()
      }
      // If no REPLACE part, keep the original content between START and END
      const originalMatch = match.match(/<!--\s*START[\s\S]*?-->[\s\S]*?<!--\s*END\s*-->/)
      return originalMatch ? originalMatch[0].replace(/<!--[\s\S]*?-->/g, "").trim() : ""
    })
  })

  return content
}

const cutPremiumFeatures = (plan) => {
  const PATH = getBuildFolderPath(plan.slug)
  const liteFilesToReplace = [
    "**/*.php",
    "**/*.js",
    "**/*.ts",
    "**/*.hbs",
    "**/*.html",
    "!.git/**",
    "!node_modules/**",
    "!js/vendor/**",
    "!vendor/**",
    "!mapsvg2/**",
    "!php/Vendor/**",
  ].map((pattern) => {
    if (pattern.startsWith("!")) {
      return `!${PATH}/${pattern.slice(1)}`
    }
    return `${PATH}/${pattern}`
  })

  console.log("Cutting project for " + plan.slug)

  return gulp
    .src(liteFilesToReplace)
    .on("data", (file) => console.log(`Matched file: ${file.path}`))
    .pipe(
      new Transform({
        objectMode: true,
        transform(file, enc, callback) {
          if (file.isBuffer()) {
            let content = file.contents.toString()
            if (file.extname === ".php") {
              content = replaceFeaturesPhpJs(content, plan.removeFeatures)
              content = replaceFeaturesHTML(content, plan.removeFeatures)
              // Add this block to change the plugin name
              if (file.path.endsWith("mapsvg.php")) {
                content = content.replace(/Plugin Name: MapSVG Dev/, "Plugin Name: " + plan.title)
                // Add the MAPSVG_PLAN constant replacement
                content = content.replace(
                  /define\('MAPSVG_PLAN'.*?;/,
                  `define('MAPSVG_PLAN', '${plan.slug}');`,
                )
                content = content.replace(
                  /define\('MAPSVG_API_URL'.*?;/,
                  `define('MAPSVG_API_URL', 'https://mapsvg.com/dashboard/api');`,
                )
                if (plan.slug === "mapsvg-lite") {
                  content = content.replace(/Text Domain: mapsvg/, "Text Domain: " + plan.slug)
                  content = content.replace(/\s*Update URI: .*\n/, "\n")
                } else {
                  content = content.replace(
                    /Update URI: .*/,
                    `Update URI: https://mapsvg.com/dashboard/api/releases/${plan.slug}/latest/`,
                  )
                }
              }
            } else if (file.extname === ".js" || file.extname === ".ts") {
              content = replaceFeaturesPhpJs(content, plan.removeFeatures)
            } else if (file.extname === ".hbs" || file.extname === ".html") {
              content = replaceFeaturesHTML(content, plan.removeFeatures)
            }
            console.log(`Writing file: ${file.path}`)
            file.contents = Buffer.from(content)
          }
          console.log("callback")
          callback(null, file)
        },
      }),
    )
    .pipe(gulp.dest(PATH))
}
gulp.task("cut-out-premium-features", function (done) {
  const currentPlan = getPlanFromCli()
  return cutPremiumFeatures(currentPlan)
})

const npmBuildProject = (plan, done) => {
  const PATH = getBuildFolderPath(plan.slug)
  console.log("Building project for " + plan.slug)
  exec("pnpm run build", { cwd: PATH }, (error, stdout, stderr) => {
    handleTerminalOutput(error, stdout, stderr)
    console.log("Building complete for " + plan.slug)
    done && done()
  })
}
gulp.task("npm-build-project", function (done) {
  const plan = getPlanFromCli()
  npmBuildProject(plan, done)
})

const npmInstall = (plan, done) => {
  const PATH = getBuildFolderPath(plan.slug)
  console.log("Installing project for " + plan.slug)
  console.log(PATH)
  exec("pnpm install", { cwd: PATH }, (error, stdout, stderr) => {
    handleTerminalOutput(error, stdout, stderr)
    console.log("Building complete for " + plan.slug)
    done && done()
  })
}
gulp.task("npm-install", function (done) {
  const currentPlan = getPlanFromCli()
})

const copyFiles = (plan, done) => {
  const PATH = getBuildFolderPath(plan.slug)
  // Check if mapsvg-lite directory exists
  if (fs.existsSync(PATH)) {
    // Delete all contents except node_modules
    fs.readdirSync(PATH).forEach((file) => {
      const currentPath = path.join(PATH, file)
      if (file !== "node_modules" && file !== ".git") {
        if (fs.lstatSync(currentPath).isDirectory()) {
          fs.rmSync(currentPath, { recursive: true, force: true })
        } else {
          fs.unlinkSync(currentPath)
        }
      }
    })
  } else {
    // If the directory doesn't exist, create it
    fs.mkdirSync(PATH)
  }

  // Copy everything except /node_modules
  fs.cpSync(BASE_PLUGIN_PATH, PATH, {
    recursive: true,
    filter: (src) => {
      const relativePath = "./" + path.relative(".", src)
      const basename = path.basename(src)
      const isMacSystemFile = basename === ".DS_Store"

      // Skip node_modules entirely in this pass
      if (
        relativePath === "./node_modules" ||
        relativePath.startsWith("./node_modules/") ||
        relativePath === "./.git" ||
        relativePath.startsWith("./.git/")
      ) {
        return false
      }

      return !plan.removeFiles?.some((excluded) => relativePath === excluded) && !isMacSystemFile
    },
  })

  done && done()
}

const setPlanName = (plan, done) => {
  const BASE_PLUGIN_PATH = getBuildFolderPath(plan.slug)
  const packageJsonPath = path.resolve(BASE_PLUGIN_PATH + "/package.json")
  const packageJson = readJSON(packageJsonPath)
  packageJson.mapsvgMeta.plan = plan.slug.replace("mapsvg-", "")
  writeJSON(packageJsonPath, packageJson)
  done && done()
}

gulp.task("copy-files", function (done) {
  const plan = getPlanFromCli()
  copyFiles(plan, done)
})

gulp.task("build-full", function (cb) {
  return gulp.parallel(
    gulp.series(
      "copy-lite-files",
      "cut-out-premium-features",
      "lite-npm-install",
      "lite-npm-build",
    ),
  )
})

const buildPlan = (plan, done) => {
  return gulp.series(
    (done) => {
      console.log(`🏗 Starting build for ${plan.slug}...`)
      done()
    },
    (done) => copyFiles(plan, done),
    (done) => setPlanName(plan, done),
    (done) => {
      return npmInstall(plan, done)
    },
    () => cutPremiumFeatures(plan),
    (done) => {
      return npmBuildProject(plan, done)
    },
    (done) => {
      console.log(`✅ Finished building ${plan.slug}`)
      done()
    },
    (done) => {
      console.log(`🏗 Starting zip files for ${plan.slug}...`)
      done()
    },
    (done) => (plan === "demo" || plan === "lite" ? done() : zipFilesTask(plan, done)),
  )(done)
}

gulp.task("build", function (done) {
  const plan = getPlanFromCli()
  return buildPlan(plan, done)
})

// Build all plans in parallel
gulp.task("build-all", function (cb) {
  return gulp.parallel(...plans.map((plan) => (done) => buildPlan(plan, done)))(cb)
})

gulp.task("test", function (cb) {
  console.log(process.env.HOME)
  cb()
  // return gulp.parallel(...plans.map((plan) => (done) => buildPlan(plan, done)))(cb)
})
