const path = require("path");
const Vibrant = require("node-vibrant");
const chroma = require("chroma-js");
const chalk = require("chalk");
const R = require("ramda");
const exifr = require("exifr");
const sharp = require('sharp');

const badContrast = (color1, color2) => chroma.contrast(color1, color2) < 4.5;

const logColorsWithContrast = (color1, color2, text) => {
  const c1hex = color1.hex();
  const c2hex = color2.hex();
  console.log(
    chalk.hex(c1hex).bgHex(c2hex)(
      `${text} ${c1hex}/${c2hex} ${chroma.contrast(color1, color2)}`
    )
  );
};

function processColors(vibrantData, imagePath) {
  let Vibrant = chroma(vibrantData.Vibrant.getRgb());
  let DarkVibrant = chroma(vibrantData.DarkVibrant.getRgb());
  let LightVibrant = chroma(vibrantData.LightVibrant.getRgb());
  let Muted = chroma(vibrantData.Muted.getRgb());
  let DarkMuted = chroma(vibrantData.DarkMuted.getRgb());
  let LightMuted = chroma(vibrantData.LightMuted.getRgb());

  // first pass - darken bg and lighten relevant fg colors
  if (
    badContrast(DarkVibrant, Vibrant) ||
    badContrast(DarkVibrant, LightMuted)
  ) {
    DarkVibrant = DarkVibrant.darken();
    if (badContrast(DarkVibrant, Vibrant)) {
      Vibrant = Vibrant.brighten();
    }
    if (badContrast(DarkVibrant, Vibrant)) {
      Vibrant = Vibrant.brighten();
    }
  }
  // second pass - first doesn't always do enough
  if (
    badContrast(DarkVibrant, Vibrant) ||
    badContrast(DarkVibrant, LightMuted)
  ) {
    if (badContrast(DarkVibrant, Vibrant)) {
      Vibrant = Vibrant.brighten(2);
    }
    if (badContrast(DarkVibrant, LightMuted)) {
      LightMuted = LightMuted.brighten(2);
    }
  }

  // only used for hover styles, so we should give it a shot but it's not a huge deal if it's not very legible
  if (badContrast(Muted, LightMuted)) {
    Muted = Muted.darken();
  }

  if (badContrast(DarkVibrant, Vibrant)) {
    console.warn("contrast still too low", imagePath);
    logColorsWithContrast(Vibrant, DarkVibrant, "V-DV");
  }
  if (badContrast(DarkVibrant, LightMuted)) {
    console.warn("contrast still too low", imagePath);
    logColorsWithContrast(LightMuted, DarkVibrant, "LM-DV");
  }

  return {
    Vibrant: Vibrant.rgb(),
    DarkVibrant: DarkVibrant.rgb(),
    LightVibrant: LightVibrant.rgb(),
    Muted: Muted.rgb(),
    DarkMuted: DarkMuted.rgb(),
    LightMuted: LightMuted.rgb(),
  };
}

// function convertDMSToDD(dms, positiveDirection) {
//   const res = dms
//     .map((item, i) => {
//       return item / Math.pow(60, i);
//     })
//     .reduce((a, b) => a + b);
//   return positiveDirection ? res : -res;
// }

// const gps = { longitude: null, latitude: null };

// if (exifData) {
//   if (exifData.gps && exifData.gps.GPSLongitude && exifData.gps.GPSLatitude) {
//     gps.longitude = convertDMSToDD(
//       exifData.gps.GPSLongitude,
//       exifData.gps.GPSLongitudeRef === "E"
//     );
//     gps.latitude = convertDMSToDD(
//       exifData.gps.GPSLatitude,
//       exifData.gps.GPSLatitudeRef === "N"
//     );
//   }
// }

function transformMetaToNodeData(metaData, vibrantData, imagePath) {
  const vibrant = vibrantData ? processColors(vibrantData, imagePath) : null;

  return {
    dateTaken: metaData.DateTimeOriginal,
    meta: metaData,
    vibrant,
  };
}

exports.onCreateNode = async function ({ node, actions }) {
  const { createNodeField } = actions;
  if (node.internal.type === "File" && node.sourceInstanceName === "gallery") {
    const metaData = await exifr.parse(node.absolutePath, {
      iptc: true,
      xmp: true,
      // icc: true
    });
    const resizedImage = await sharp(node.absolutePath)
      .resize({
        width: 3000,
        height: 3000,
        fit: 'inside'
      })
      .toBuffer()
    const vibrantData = await Vibrant.from(resizedImage)
      .quality(1)
      .getPalette();

    createNodeField({
      node,
      name: "imageMeta",
      value: transformMetaToNodeData(metaData, vibrantData, node.absolutePath),
    });
  }
};

// Implement the Gatsby API “createPages”. This is called once the
// data layer is bootstrapped to let plugins create pages from data.
exports.createPages = async ({ graphql, actions, reporter }) => {
  const { createPage } = actions;
  // get all images
  const galleryImages = await graphql(`
    {
      allFile(filter: { sourceInstanceName: { eq: "gallery" } }) {
        edges {
          node {
            relativePath
            base
            fields {
              imageMeta {
                dateTaken
              }
            }
          }
        }
      }
    }
  `);
  // Handle errors
  if (galleryImages.errors) {
    reporter.panicOnBuild("Error while running GraphQL query.");
    return;
  }
  // Create pages for each markdown file.
  const galleryImageTemplate = path.resolve(
    "src/components/GalleryImage/GalleryImage.js"
  );
  // const diffDate = (a, b) =>
  //   new Date(R.path(['node', 'childImageSharp', 'fields', 'imageMeta', 'dateTaken'], a)).getTime() - new Date(R.path(['node', 'childImageSharp', 'fields', 'imageMeta', 'dateTaken'],b)).getTime();

  const edges = R.sort(
    R.descend(
      (edge) =>
        new Date(R.path(["node", "fields", "imageMeta", "dateTaken"], edge))
    ),
    galleryImages.data.allFile.edges
  );

  edges.forEach(({ node }, index) => {
    const nextImage =
      index === edges.length - 1 ? null : edges[index + 1].node.base;
    const prevImage = index === 0 ? null : edges[index - 1].node.base;
    const page = {
      path: `photogallery/${node.base}`,
      component: galleryImageTemplate,
      context: {
        imageFilename: node.base,
        nextImage,
        prevImage,
      },
    };
    createPage(page);
  });
};