#!/usr/bin/perl -w

use strict;
use warnings;
use FindBin;
use lib "$FindBin::Bin/../lib"; # t/lib
use Test::More;
use MT::Test::Env;
BEGIN {
    eval { require Test::MockModule }
        or plan skip_all => 'Test::MockModule is not installed';
}

our $test_env;
BEGIN {
    $test_env = MT::Test::Env->new;
    $ENV{MT_CONFIG} = $test_env->config_file;
}

use MT::Test;
use MT::Image;
use MT::Test::Image;
use File::Temp;
use File::Copy;
use Image::ExifTool;

$test_env->prepare_fixture('db');

my ( $guard, $src_file ) = MT::Test::Image->tempfile(
    DIR    => $test_env->root,
    SUFFIX => '.jpg',
);
close $guard;

my $site = MT::Blog->load(1);

my $src_image = MT::Image->new( Filename => $src_file );
$src_image->_init_image_size;

sub _create_image_with_orientation {
    my ($orientation) = @_;
    my $exifTool = new Image::ExifTool;
    $exifTool->SetNewValue(
        Orientation => $orientation,
        Type        => 'ValueConv'
    );
    my ( $fh, $file ) = File::Temp::tempfile(
        SUFFIX => '.jpg',
        DIR    => $site->site_path,
    );
    close($fh);
    copy( $src_file, $file );
    $exifTool->WriteInfo($file);

    $file;
}

my %map = (
    1 => {
        put            => 0,
        flipHorizontal => 0,
        flipVertical   => 0,
        rotate         => 0,
        width          => $src_image->{width},
        height         => $src_image->{height},
    },
    2 => {
        put            => 1,
        flipHorizontal => 1,
        flipVertical   => 0,
        rotate         => 0,
        width          => $src_image->{width},
        height         => $src_image->{height},
    },
    3 => {
        put            => 1,
        flipHorizontal => 0,
        flipVertical   => 0,
        rotate         => 180,
        width          => $src_image->{width},
        height         => $src_image->{height},
    },
    4 => {
        put            => 1,
        flipHorizontal => 0,
        flipVertical   => 1,
        rotate         => 0,
        width          => $src_image->{width},
        height         => $src_image->{height},
    },
    5 => {
        put            => 1,
        flipHorizontal => 1,
        flipVertical   => 0,
        rotate         => 270,
        width          => $src_image->{height},
        height         => $src_image->{width},
    },
    6 => {
        put            => 1,
        flipHorizontal => 0,
        flipVertical   => 0,
        rotate         => 90,
        width          => $src_image->{height},
        height         => $src_image->{width},
    },
    7 => {
        put            => 1,
        flipHorizontal => 1,
        flipVertical   => 0,
        rotate         => 90,
        width          => $src_image->{height},
        height         => $src_image->{width},
    },
    8 => {
        put            => 1,
        flipHorizontal => 0,
        flipVertical   => 0,
        rotate         => 270,
        width          => $src_image->{height},
        height         => $src_image->{width},
    },
);

sub _run {
    for my $orientation ( 1 .. 8 ) {
        my $expected = $map{$orientation};
        subtest 'Orientation: ' . $orientation => sub {
            my $file = _create_image_with_orientation($orientation);

            my %counter = ();

            my $fmgr_module = Test::MockModule->new('MT::FileMgr::Local');
            $fmgr_module->mock(
                'put_data',
                sub {
                    $counter{put}++;
                    $fmgr_module->original('put_data')->(@_);
                }
            );

            my $image_obj        = MT::Image->new( Filename => $file );
            my $image_module     = Test::MockModule->new( ref $image_obj );
            $image_module->mock(
                'flipHorizontal',
                sub {
                    $counter{flipHorizontal}++;
                    $image_module->original('flipHorizontal')->(@_);
                }
            );
            $image_module->mock(
                'flipVertical',
                sub {
                    $counter{flipVertical}++;
                    $image_module->original('flipVertical')->(@_);
                }
            );
            $image_module->mock(
                'rotate',
                sub {
                    my ( $self, %params ) = @_;
                    $counter{rotate} += $params{Degrees};
                    $image_module->original('rotate')->(@_);
                }
            );

            my $asset = MT::Asset::Image->new;
            $asset->blog_id(1);
            $asset->file_path($file);
            $asset->file_ext('jpg');
            $asset->image_width( $image_obj->{width} );
            $asset->image_height( $image_obj->{height} );

            $asset->normalize_orientation;

            is( $asset->image_width,  $expected->{width},  'Updated width' );
            is( $asset->image_height, $expected->{height}, 'Updated height' );
            if ( $expected->{rotate} == 0 ) {
                is( $counter{rotate} || 0, 0, 'rotate is not called' );
            }
            else {
                is( $counter{rotate} || 0,
                    $expected->{rotate},
                    'rotate is called (Degrees:' . $expected->{rotate} . ')'
                );
            }
            for my $k (qw(put flipHorizontal flipVertical)) {
                next unless exists $expected->{$k};
                is( $counter{$k} || 0,
                    $expected->{$k},
                    $k . ' is called ' . $expected->{$k} . ' time(s)' );
            }

            my $fixed_orientation = Image::ExifTool::ImageInfo($file)->{Orientation};
            is( $fixed_orientation => 'Horizontal (normal)', 'Orientation is set to normal');
        };
    }
}

for my $driver ( $test_env->image_drivers ) {
    subtest $driver => sub {
        my ( $guard, $file ) = MT::Test::Image->tempfile(
            DIR    => $test_env->root,
            SUFFIX => '.png',
        );
        close $guard;

        my $cfg = MT::ConfigMgr->instance;
        $cfg->ImageDriver($driver);
        MT::Image->error('');
        MT::Image->new( Filename => $file )
            or plan skip_all => "Cannot load MT::Image::$driver";

        _run();
    };
}

done_testing();
