/*!
  Copyright 2013 Lovell Fuller and others.
  SPDX-License-Identifier: Apache-2.0
*/

const { describe, it } = require('node:test');
const assert = require('node:assert');

const sharp = require('../../');
const fixtures = require('../fixtures');

const sepia = [
  [0.3588, 0.7044, 0.1368],
  [0.299, 0.587, 0.114],
  [0.2392, 0.4696, 0.0912]
];

describe('Recomb', () => {
  it('applies a sepia filter using recomb', (_t, done) => {
    const output = fixtures.path('output.recomb-sepia.jpg');
    sharp(fixtures.inputJpgWithLandscapeExif1)
      .recomb(sepia)
      .toFile(output, (err, info) => {
        if (err) throw err;
        assert.strictEqual('jpeg', info.format);
        assert.strictEqual(600, info.width);
        assert.strictEqual(450, info.height);
        fixtures.assertMaxColourDistance(
          output,
          fixtures.expected('Landscape_1-recomb-sepia.jpg'),
          17
        );
        done();
      });
  });

  it('applies a sepia filter using recomb to an PNG with Alpha', (_t, done) => {
    const output = fixtures.path('output.recomb-sepia.png');
    sharp(fixtures.inputPngAlphaPremultiplicationSmall)
      .recomb(sepia)
      .toFile(output, (err, info) => {
        if (err) throw err;
        assert.strictEqual('png', info.format);
        assert.strictEqual(1024, info.width);
        assert.strictEqual(768, info.height);
        fixtures.assertMaxColourDistance(
          output,
          fixtures.expected('alpha-recomb-sepia.png'),
          17
        );
        done();
      });
  });

  it('recomb with a single channel input', async () => {
    const { info } = await sharp(Buffer.alloc(64), {
      raw: {
        width: 8,
        height: 8,
        channels: 1
      }
    })
      .recomb(sepia)
      .toBuffer({ resolveWithObject: true });

    assert.strictEqual(3, info.channels);
  });

  it('applies a different sepia filter using recomb', (_t, done) => {
    const output = fixtures.path('output.recomb-sepia2.jpg');
    sharp(fixtures.inputJpgWithLandscapeExif1)
      .recomb([
        [0.393, 0.769, 0.189],
        [0.349, 0.686, 0.168],
        [0.272, 0.534, 0.131]
      ])
      .toFile(output, (err, info) => {
        if (err) throw err;
        assert.strictEqual('jpeg', info.format);
        assert.strictEqual(600, info.width);
        assert.strictEqual(450, info.height);
        fixtures.assertMaxColourDistance(
          output,
          fixtures.expected('Landscape_1-recomb-sepia2.jpg'),
          17
        );
        done();
      });
  });
  it('increases the saturation of the image', (_t, done) => {
    const saturationLevel = 1;
    const output = fixtures.path('output.recomb-saturation.jpg');
    sharp(fixtures.inputJpgWithLandscapeExif1)
      .recomb([
        [
          saturationLevel + 1 - 0.2989,
          -0.587 * saturationLevel,
          -0.114 * saturationLevel
        ],
        [
          -0.2989 * saturationLevel,
          saturationLevel + 1 - 0.587,
          -0.114 * saturationLevel
        ],
        [
          -0.2989 * saturationLevel,
          -0.587 * saturationLevel,
          saturationLevel + 1 - 0.114
        ]
      ])
      .toFile(output, (err, info) => {
        if (err) throw err;
        assert.strictEqual('jpeg', info.format);
        assert.strictEqual(600, info.width);
        assert.strictEqual(450, info.height);
        fixtures.assertMaxColourDistance(
          output,
          fixtures.expected('Landscape_1-recomb-saturation.jpg'),
          37
        );
        done();
      });
  });

  it('applies opacity 30% to the image', (_t, done) => {
    const output = fixtures.path('output.recomb-opacity.png');
    sharp(fixtures.inputPngWithTransparent)
      .recomb([
        [1, 0, 0, 0],
        [0, 1, 0, 0],
        [0, 0, 1, 0],
        [0, 0, 0, 0.3]
      ])
      .toFile(output, (err, info) => {
        if (err) throw err;
        assert.strictEqual('png', info.format);
        assert.strictEqual(48, info.width);
        assert.strictEqual(48, info.height);
        fixtures.assertMaxColourDistance(
          output,
          fixtures.expected('d-opacity-30.png'),
          17
        );
        done();
      });
  });

  describe('invalid matrix specification', () => {
    it('missing', () => {
      assert.throws(() => {
        sharp(fixtures.inputJpg).recomb();
      });
    });
    it('incorrect flat data', () => {
      assert.throws(() => {
        sharp(fixtures.inputJpg).recomb([1, 2, 3, 4, 5, 6, 7, 8, 9]);
      });
    });
    it('incorrect sub size', () => {
      assert.throws(() => {
        sharp(fixtures.inputJpg).recomb([
          [1, 2, 3, 4],
          [5, 6, 7, 8],
          [1, 2, 9, 6]
        ]);
      });
    });
    it('incorrect top size', () => {
      assert.throws(() => {
        sharp(fixtures.inputJpg).recomb([[1, 2, 3, 4], [5, 6, 7, 8]]);
      });
    });
  });
});
