#!/usr/bin/perl
use strict;
use warnings;

package API::Banner;

use MIME::Base64;
use MIME::Entity;
use MIME::Lite;

use ECS::CDN::S3;
use SOAP::Lite ();
use base 'SOAP::Server::Parameters';

use API::Config;
my $Config = $API::Config::Config;
use lib $API::Config::Config->{'Website_libs'};

use ECS::Config;
use ECS::SQL;
use ECS::Site;

use ECS::Messaging::Queue::AmazonSQS;
use ECS::Endeca::Updates::Banner::Producer;

use Image::Magick;
use Try::Tiny;

sub add {
    my $ref = shift;
    my $input = shift;

    my $result = {
        'success'    => 1,
        'update_DB'    => $Config->{update_DB},
        'write_image' => $Config->{write_image},
        'row'        => ''
    };

    #insert
    $input->{bnrAlias} =~ tr/ /_/;
    $input->{bnrAlias} =~ s/[^a-zA-Z0-9_]//g;

    my $DBH = ECS::SQL::connect();

    my $row = ECS::SQL::insert({
        DBH => $DBH,
        table =>'banner',
        columns => [qw(name date weight enabled target alias homepage siteID dateExpired dateCampaigned)],
        hash => {
            name=>$input->{bnrTitle},
            date=>$input->{date},
            weight=>$input->{weight},
            enabled=>$input->{enabled},
            target=>$input->{target},
            alias=>$input->{bnrAlias},
            homepage=>$input->{homepage},
            siteID=>$input->{siteID},
            dateExpired=>$input->{dateExpired},
            dateCampaigned=>$input->{dateCampaigned},
        }
    });
    my $banner_id = $row;
    if(!defined($row)){
        $result->{success} = 0;
        $result->{error} = "Unable to add banner to DB.";
        return $result;
    }

    # upload and move the image.
    if($input->{image} and $result->{success}){
        if(!ECS::SQL::update({
            DBH=>$DBH,
            table=>'banner',
            key=>'banner_id',
            columns=>[qw(path banner_id)],
            hash=>{path=>$input->{filename},banner_id=>$row}
        })){
            $result->{success} = 0;
            $result->{error} = "Unable to add banner image.";
            return $result;
        };
    }
    $result->{row} = $row;

    my $producer = _getEndecaUpdateProducer();
    $producer->publish($banner_id, 'create');

    return $result;
}

sub update {

    my $ref = shift;
    my $input = shift;

    my $result = {
        'success'    => 1,
        'update_DB'    => $Config->{update_DB},
        'write_image'    => $Config->{write_image}
    };

    my $DBH = ECS::SQL::connect();

    if($input->{bannerid} ne 'new'){
        $input->{bnrAlias} =~ tr/ /_/;
        $input->{bnrAlias} =~ s/[^a-zA-Z0-9_]//g;
        if(!ECS::SQL::update({
            DBH=>$DBH,
            table=>'banner',
            key=>'banner_id',
            columns=>[qw(name date weight enabled target alias homepage banner_id siteID dateExpired dateCampaigned)],
            hash=>{
                name=>$input->{bnrTitle},
                date=>$input->{date},
                weight=>$input->{weight},
                enabled=>$input->{enabled},
                target=>$input->{target},
                alias=>$input->{bnrAlias},
                homepage=>$input->{homepage},
                banner_id=>$input->{bannerid},
                siteID=>$input->{siteID},
                dateExpired=>$input->{dateExpired},
                dateCampaigned=>$input->{dateCampaigned},
            }
        })){
            $result->{success} = 0;
            $result->{error} = "Unable to update banner.";
            return $result;
        };
    }

    # If it has an image -- update the image info in the DB
    # -----------------------------------------------------
    if($input->{image}){
        if(!ECS::SQL::update({
            DBH=>$DBH,
            table=>'banner',
            key=>'banner_id',
            columns=>[qw(path banner_id)],
            hash=>{path=>$input->{filename},banner_id=>$input->{bannerid}}
        })){
            $result->{success} = 0;
            $result->{error} = "Unable to update banner image.";
            return $result;
        };
    }

    my $producer = _getEndecaUpdateProducer();
    $producer->publish($input->{'bannerid'}, 'update');

    return $result;
}

sub delete {

    my $ref = shift;
    my $input = shift;

    my $result = {
        'success'    => 1,
        'error'        => undef,
        'update_DB'    => $Config->{update_DB},
    };

    my $DBH = ECS::SQL::connect();

    # Delete (unlink) the specified file from the following locations:
    # ----------------------------------------------------------------
    #unlink($Config->{image_uploads}."/banner/".$input->{filename});

    ECS::SQL::delete({
          DBH => $DBH,
          table => 'banner',
          columns => [qw(banner_id)],
          hash => {banner_id=>$input->{delbannerid}}
    });

    my $producer = _getEndecaUpdateProducer();
    $producer->publish($input->{delbannerid}, 'delete');

    return $result;
}

sub image {
    my $self = shift;
    my $input = shift;
    my $envelope = pop;

    my $result = {
        'success'    => 1,
        'error'        => undef,
        'update_DB'    => $Config->{update_DB}
    };

    my $containerName = 'static';

    # In case of ECS, siteID might not be passed
    $input->{siteID} ||= 1;
    my $site = ECS::Site->fromID($input->{siteID});
    if ($site->name eq 'TMS') {
        $containerName = 'static_tms';
    }

    my $s3 = ECS::CDN::S3->new();

    my $filePath;
    my $webpFileName;
    my $webpFilePath;

    # Upload image to image_uploads when write_image is true (API::Config)
    # ------------------------------------------------------------------
    if ($Config->{write_image}){
        my $of;
        $filePath = "$Config->{image_uploads}/banners/$input->{filename}";

        if (!open($of, ">$filePath")) {
            $result->{success} = 0;
            $result->{error} = "Unable to open file for writing: $filePath";
            return $result;
        }

        my @parts = $envelope->parts();
        my $part = $parts[0]->[0];
        print $of $part->bodyhandle->as_string;
        close($of);

        $webpFileName = $input->{filename};
        $webpFileName =~ s/\.jpg/.webp/;
        $webpFilePath = "$Config->{image_uploads}/banners/$webpFileName";

        # create webp, defaults to quality 75
        `$Config->{cwebpExec} $filePath -metadata all -quiet -o $webpFilePath`;
        unless (-e $webpFilePath) {
            $result->{success} = 0;
            $result->{error} = "Unable to create webp: $webpFilePath";
            return $result;
        }

        # set the quality / compression on JPG
        my $image = Image::Magick->new;
        $image->Read("$filePath");
        if ($image->Get('quality') > 85) {
            $image->Write(filename => $filePath, compression => 'JPEG', quality => 85, 'sampling-factor' => '4:2:0');
        } else {
            $image->Write(filename => $filePath, compression => 'JPEG', 'sampling-factor' => '4:2:0');
        }
    }

    # Upload the same file to S3
    # ----------------------------------------
    if ($Config->{write_cloud}) {
        my $jpeg_banner_object = "$containerName/img/banners/$input->{filename}";
        my $webp_banner_object = "$containerName/img/banners/$webpFileName";
        my $upload_error_message;
        try {
            $s3->put_file(
                $jpeg_banner_object,
                $filePath,
                {
                    'Content-Type'        => 'image/jpeg',
                    'Content-Disposition' => 'inline',    # Images uploaded will preview only when this line is added
                }
            );
            1;
        } catch {
            $upload_error_message = "Failed to upload $filePath to $jpeg_banner_object";
            $result->{success} = 0;
            $result->{error} = $upload_error_message;
            warn $upload_error_message;
            0;
        } or return $result;

        try {
            $s3->put_file(
                $webp_banner_object,
                $webpFilePath,
                {
                    'Content-Type'        => 'image/webp',
                    'Content-Disposition' => 'inline',
                }
            );
            1;
        } catch {
            $upload_error_message = "Failed to upload $webpFilePath to $webp_banner_object";
            $result->{success} = 0;
            $result->{error} = $upload_error_message;
            warn $upload_error_message;
            0;
        } or return $result;
    }

    return $result;
}

sub _getEndecaUpdateProducer {

    my $queue = ECS::Messaging::Queue::AmazonSQS->new({
        'accessKey' => $ECS::Config::c{'sqsAccessKey'},
        'secretKey' => $ECS::Config::c{'sqsSecretKey'},
        'queueUri'  => $ECS::Config::c{'sqsPartialUpdateQueue'}->{'uri'},
        'queueType' => $ECS::Config::c{'sqsPartialUpdateQueue'}->{'type'},
    });

    return ECS::Endeca::Updates::Banner::Producer->new({
        'queue' => $queue,
    });
}

1;
