import gulp from 'gulp';
import twig from 'gulp-twig';
import * as dartSass from 'sass';
import gulpSass from 'gulp-sass';
import autoprefixer from 'gulp-autoprefixer';
import browserSync from 'browser-sync';
import babel from 'gulp-babel';
import concat from 'gulp-concat';
import uglify from 'gulp-uglify';
import imagemin from 'gulp-imagemin';
import cleanCss from 'gulp-clean-css';
import { deleteAsync } from 'del';
import sourcemaps from 'gulp-sourcemaps';
import fs from 'fs';
import plumber from 'gulp-plumber';
import svgstore from 'gulp-svgstore';
import cheerio from 'gulp-cheerio';
import through2 from 'through2';
import data from 'gulp-data';
import path from 'path';
import webp from 'gulp-webp';
import rev from 'gulp-rev';
import revReplace from 'gulp-rev-replace';
import cached from 'gulp-cached';
import remember from 'gulp-remember';
import { exec } from 'child_process';
import puppeteer from 'puppeteer';
import postcss from 'gulp-postcss';

import { fileURLToPath } from 'url';
import { dirname } from 'path';

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

const sass = gulpSass(dartSass);
browserSync.create();

const cleanTask = () => {
  return deleteAsync(['dist']);
};

const lintJsTask = (cb) => {
  exec('npx @biomejs/biome check src/js', (err, stdout, stderr) => {
    console.log(stdout);
    console.error(stderr);
    if (err) {
      console.error('Biome check failed!', err);
      return cb(err);
    }
    cb();
  });
};

const formatJsTask = (cb) => {
  exec('npx @biomejs/biome format --write src/js', (err, stdout, stderr) => {
    console.log(stdout);
    console.error(stderr);
    if (err) {
      console.error('Biome format failed!', err);
      return cb(err);
    }
    cb();
  });
};

export const svgSpriteTask = (cb) => {
  let svgContent = '';
  return gulp.src('src/icons/**/*.svg')
    .pipe(cached('svgIcons')) // Cache SVG icons
    .pipe(plumber())
    .pipe(cheerio({
      run: function ($) {
        $('[fill]').removeAttr('fill');
        $('[stroke]').removeAttr('stroke');
        $('[style]').removeAttr('style');
      },
      parserOptions: { xmlMode: true }
    }))
    .pipe(svgstore({
      inlineSvg: true
    }))
    .pipe(remember('svgIcons')) // Remember all SVG icons
    .pipe(through2.obj(function (file, enc, cb2) {
      svgContent = file.contents.toString();
      cb2(null, file);
    }))
    .pipe(gulp.dest('dist')) // Still write to dist for consistency
    .on('end', () => {
      // Ensure the file is written before calling the callback
      fs.promises.writeFile('./dist/svg-sprite.svg', svgContent)
        .then(cb)
        .catch(cb);
    });
};

const twigTask = () => {
  const globalData = JSON.parse(fs.readFileSync('./src/data/global.json'));
  const svgSprite = fs.readFileSync('./dist/svg-sprite.svg', 'utf8');

  return gulp.src('src/templates/*.twig') // Process only top-level twig files
    .pipe(cached('twigTemplates')) // Cache twig templates
    .pipe(plumber())
    .pipe(data(function(file) {
      const fileName = path.basename(file.path, '.twig');
      const dataFilePath = `./src/data/${fileName}.json`;
      let pageData = {};
      if (fs.existsSync(dataFilePath)) {
        pageData = JSON.parse(fs.readFileSync(dataFilePath));
      }
      return { ...globalData, ...pageData, svgSprite: svgSprite };
    }))
    .pipe(twig())
    .pipe(remember('twigTemplates')) // Remember all twig templates
    .pipe(gulp.dest('dist'))
    .pipe(browserSync.stream());
};

const scssTask = () => {
  return gulp.src('src/scss/main.scss')
    .pipe(cached('scss')) // Cache SCSS files
    .pipe(plumber())
    .pipe(sourcemaps.init())
    .pipe(sass().on('error', sass.logError))
    .pipe(autoprefixer())
    .pipe(sourcemaps.write('.'))
    .pipe(remember('scss')) // Remember all SCSS files
    .pipe(gulp.dest('dist'))
    .pipe(browserSync.stream());
};

const scssProdTask = () => {
  return gulp.src('src/scss/main.scss')
    .pipe(cached('scssProd')) // Cache SCSS files for prod
    .pipe(plumber())
    .pipe(sass().on('error', sass.logError))
    .pipe(autoprefixer())
    
    .pipe(cleanCss())
    .pipe(remember('scssProd')) // Remember all SCSS files for prod
    .pipe(gulp.dest('dist'));
};

const jsDevTask = () => {
  return gulp.src('src/js/**/*.js')
    .pipe(cached('jsDev')) // Cache JS files for dev
    .pipe(plumber())
    .pipe(babel({
      presets: ['@babel/env']
    }))
    .pipe(concat('main.js'))
    .pipe(sourcemaps.write('.'))
    .pipe(remember('jsDev')) // Remember all JS files for dev
    .pipe(gulp.dest('dist/js'))
    .pipe(browserSync.stream());
};

const jsMinTask = () => {
  return gulp.src(['src/js/**/*.js', '!src/js/**/*.test.js'])
    .pipe(cached('jsProd')) // Cache JS files for prod
    .pipe(plumber())
    .pipe(sourcemaps.init())
    .pipe(babel({
      presets: ['@babel/env']
    }))
    .pipe(concat('main.min.js'))
    .pipe(uglify())
    .pipe(sourcemaps.write('.'))
    .pipe(remember('jsProd')) // Remember all JS files for prod
    .pipe(gulp.dest('dist/js'))
    .pipe(browserSync.stream());
};

const jsTask = () => {
  return gulp.src(['src/js/**/*.js', '!src/js/**/*.test.js'])
    .pipe(cached('jsProd')) // Cache JS files for prod
    .pipe(plumber())
    .pipe(sourcemaps.init())
    .pipe(babel({
      presets: ['@babel/env']
    }))
    .pipe(concat('main.js'))
    .pipe(sourcemaps.write('.'))
    .pipe(remember('jsProd')) // Remember all JS files for prod
    .pipe(gulp.dest('dist/js'))
    .pipe(browserSync.stream());
};

const imagesTask = () => {
  return gulp.src('src/images/*')
    .pipe(cached('images')) // Cache images
    .pipe(plumber())
    .pipe(imagemin())
    .pipe(remember('images')) // Remember all images
    .pipe(gulp.dest('dist/images'))
    .pipe(browserSync.stream());
};

const imagesProdTask = () => {
  return gulp.src('src/images/*')
    .pipe(cached('imagesProd')) // Cache images for prod
    .pipe(plumber())
    .pipe(imagemin())
    .pipe(gulp.dest('dist/images'))
    .pipe(webp())
    .pipe(gulp.dest('dist/images'));
};

const copyAssetsTask = () => {
  return gulp.src('src/assets/**/*')
    .pipe(cached('assets')) // Cache assets
    .pipe(plumber())
    .pipe(remember('assets')) // Remember all assets
    .pipe(gulp.dest('dist/assets'))
    .pipe(browserSync.stream());
};

const copyFaviconTask = () => {
  return gulp.src('src/favicon.ico')
    .pipe(cached('favicon')) // Cache favicon
    .pipe(plumber())
    .pipe(remember('favicon')) // Remember favicon
    .pipe(gulp.dest('dist'))
    .pipe(browserSync.stream());
};

const copyFontsTask = () => {
  return gulp.src('src/fonts/**/*')
    .pipe(cached('fonts')) // Cache fonts
    .pipe(plumber())
    .pipe(remember('fonts')) // Remember all fonts
    .pipe(gulp.dest('dist/fonts'))
    .pipe(browserSync.stream());
};

const revTask = () => {
  return gulp.src(['dist/**/*.css', 'dist/**/*.js'], { base: 'dist' })
    .pipe(gulp.dest('dist')) // write original assets to dist
    .pipe(rev())
    .pipe(gulp.dest('dist')) // write rev'd assets to dist
    .pipe(rev.manifest())
    .pipe(gulp.dest('dist')); // write manifest to dist
};

const revReplaceTask = () => {
  const manifest = gulp.src('dist/rev-manifest.json');

  return gulp.src('dist/**/*.html')
    .pipe(revReplace({ manifest: manifest }))
    .pipe(gulp.dest('dist'));
};

const screenshotsTask = async () => {
  const browser = await puppeteer.launch();
  const page = await browser.newPage();
  const resolutions = [
    { width: 1920, height: 1080, name: 'desktop' },
    { width: 1366, height: 768, name: 'laptop' },
    { width: 768, height: 1024, name: 'tablet' },
    { width: 375, height: 667, name: 'mobile' },
  ];

  // Ensure the screenshots directory exists
  if (!fs.existsSync('dist/screenshots')) {
    fs.mkdirSync('dist/screenshots');
  }

  for (const res of resolutions) {
    await page.setViewport({ width: res.width, height: res.height });
    await page.goto('file://' + path.resolve(__dirname, 'dist/index.html'));
    await page.screenshot({ path: `dist/screenshots/screenshot-${res.name}-${res.width}x${res.height}.png` });
    console.log(`Screenshot captured for ${res.name} (${res.width}x${res.height})`);
  }

  await browser.close();
};


const watchTask = () => {
  browserSync.init({
    server: {
      baseDir: './dist'
    },
    https: true // Enable HTTPS
  });
  gulp.watch('src/templates/**/*.twig', twigTask);
  gulp.watch('src/scss/**/*.scss', scssTask);
  gulp.watch('src/js/**/*.js', gulp.series(lintJsTask, jsDevTask));
  gulp.watch('src/images/*', imagesTask);
  gulp.watch('src/data/**/*.json', twigTask);
  gulp.watch('src/assets/**/*', copyAssetsTask);
  gulp.watch('src/favicon.ico', copyFaviconTask);
  gulp.watch('src/icons/**/*.svg', gulp.series(svgSpriteTask, twigTask)); // Watch for changes in SVG icons
  gulp.watch('src/fonts/**/*', copyFontsTask); // Watch for changes in fonts
};

const devBuild = gulp.series(cleanTask, svgSpriteTask, gulp.parallel(scssTask, jsDevTask, imagesTask, copyAssetsTask, copyFaviconTask, copyFontsTask), twigTask);

export const build = gulp.series(cleanTask, lintJsTask, svgSpriteTask, twigTask, gulp.parallel(scssTask, jsDevTask, imagesTask, copyAssetsTask, copyFaviconTask, copyFontsTask));
export const buildProd = gulp.series(cleanTask, lintJsTask, svgSpriteTask, twigTask, gulp.parallel(scssProdTask, jsTask, jsMinTask, imagesProdTask, copyAssetsTask, copyFaviconTask, copyFontsTask), revTask, revReplaceTask, screenshotsTask);
export const screenshots = screenshotsTask;
export default gulp.series(devBuild, watchTask);
