package SL::Controller::DeliveryOrder::TypeData;

use strict;
use Exporter qw(import);
use Scalar::Util qw(weaken);
use SL::Locale::String qw(t8);

use constant {
  SALES_ORDER_TYPE => 'sales_order',
  PURCHASE_ORDER_TYPE => 'purchase_order',
  SALES_QUOTATION_TYPE => 'sales_quotation',
  REQUEST_QUOTATION_TYPE => 'request_quotation'
};

our @EXPORT_OK = qw(SALES_ORDER_TYPE PURCHASE_ORDER_TYPE SALES_QUOTATION_TYPE REQUEST_QUOTATION_TYPE);

use Rose::Object::MakeMethods::Generic scalar => [ qw(c) ];

my %type_data = (
  SALES_ORDER_TYPE() => {
    text => {
      delete => t8('The order has been deleted'),
      saved  => t8('The order has been saved'),
      add    => t8("Add Sales Order"),
      edit   => t8("Edit Sales Order"),
    },
    show_menu => {
      save_and_quotation      => 1,
      save_and_rfq            => 0,
      save_and_sales_order    => 0,
      save_and_purchase_order => 1,
      save_and_delivery_order => 1,
      save_and_ap_transaction => 0,
      delete                  => sub { $::instance_conf->get_sales_order_show_delete },
    },
    workflow => {
      to_order_type        => "purchase_order",
      to_quotation_type    => "sales_quotation",
      to_order_copy_shipto => 1,
    },
    properties => {
      customervendor => "customer",
      is_quotation   => 0,
      nr_key         => "ordnumber",
    },
    part_classification_query => [ "used_for_sale" => 1 ],
    right => "sales_order_edit",
  },
  PURCHASE_ORDER_TYPE() => {
    text =>{
      delete => t8('The order has been deleted'),
      saved  => t8('The order has been saved'),
      add    => t8("Add Purchase Order"),
      edit   => t8("Edit Purchase Order"),
    },
    show_menu => {
      save_and_quotation      => 0,
      save_and_rfq            => 1,
      save_and_sales_order    => 1,
      save_and_purchase_order => 0,
      save_and_delivery_order => 1,
      save_and_ap_transaction => 1,
      delete                  => sub { $::instance_conf->get_purchase_order_show_delete },
    },
    workflow => {
      to_order_type        => "sales_order",
      to_quotation_type    => "request_quotation",
      to_order_copy_shipto => 0,
    },
    properties => {
      customervendor => "vendor",
      is_quotation   => 0,
      nr_key         => "ordnumber",
    },
    part_classification_query => [ "used_for_purchase" => 1 ],
    right => "purchase_order_edit",
  },
  SALES_QUOTATION_TYPE() => {
    text => {
      delete => t8('The quotation has been deleted'),
      saved  => t8('The quotation has been saved'),
      add    => t8("Add Quotation"),
      edit   => t8("Edit Quotation"),
    },
    show_menu => {
      save_and_quotation      => 0,
      save_and_rfq            => 0,
      save_and_sales_order    => 1,
      save_and_purchase_order => 0,
      save_and_delivery_order => 0,
      save_and_ap_transaction => 0,
      delete                  => 1,
    },
    workflow => {
      to_order_type        => "sales_order",
      to_quotation_type    => "request_quotation",
      to_order_copy_shipto => 0,
    },
    properties => {
      customervendor => "customer",
      is_quotation   => 1,
      nr_key         => "quonumber",
    },
    part_classification_query => [ "used_for_sale" => 1 ],
    right => "sales_quotation_edit",
  },
  REQUEST_QUOTATION_TYPE() => {
    text => {
      delete => t8('The rfq has been deleted'),
      saved  => t8('The rfq has been saved'),
      add    => t8("Add Request for Quotation"),
      edit   => t8("Edit Request for Quotation"),
    },
    show_menu => {
      save_and_quotation      => 0,
      save_and_rfq            => 0,
      save_and_sales_order    => 0,
      save_and_purchase_order => 1,
      save_and_delivery_order => 0,
      save_and_ap_transaction => 0,
      delete                  => 1,
    },
    workflow => {
      to_order_type        => "purchase_order",
      to_quotation_type    => "request_quotation",
      to_order_copy_shipto => 0,
    },
    properties => {
      customervendor => "vendor",
      is_quotation   => 1,
      nr_key         => "quonumber",
    },
    part_classification_query => [ "used_for_purchase" => 1 ],
    right => "request_quotation_edit",
  },
);

sub new {
  my ($class, $controller) = @_;
  my $o = bless {}, $class;
  $o->c($controller);
  weaken($o->{c});

  return $o;
}

sub valid_types {
  [
    SALES_ORDER_TYPE,
    PURCHASE_ORDER_TYPE,
    SALES_QUOTATION_TYPE,
    REQUEST_QUOTATION_TYPE,
  ];
}

sub type {
  $_[0]->c->type;
}

sub get {
  my ($self, $key) = @_;

  my $ret = $type_data{$self->type}->{$key} // die "unknown property '$key'";

  ref $ret eq 'CODE'
    ? $ret->()
    : $ret;
}

sub _get3 {
  my ($self, $topic, $key) = @_;

  my $ret = $type_data{$self->type}->{$topic}->{$key} // die "unknown property '$key' in topic '$topic'";

  ref $ret eq 'CODE'
    ? $ret->()
    : $ret;
}

sub text {
  my ($self, $string) = @_;
  _get3($self, "text", $string);
}

sub show_menu {
  my ($self, $string) = @_;
  _get3($self, "show_menu", $string);
}

sub workflow {
  my ($self, $string) = @_;
  _get3($self, "workflow", $string);
}

sub properties {
  my ($self, $string) = @_;
  _get3($self, "properties", $string);
}

sub is_valid_type {
  !!exists $type_data{$_[1]};
}

sub type_data {
  $type_data{ $_[0]->type } // die "unknown type";
}

sub access {
  $type_data{right};
}

sub is_quotation {
  _get3($_[0], "properties", "is_quotation");
}

sub customervendor {
  _get3($_[0], "properties", "customervendor");
}

sub nr_key {
  _get3($_[0], "properties", "nr_key");
}

sub part_classification_query {
  my ($self, $string) = @_;
  _get($self, "part_classification_query");
}

sub set_reqdate_by_type {
  my ($self) = @_;

  my $extra_days = $self->type eq SALES_QUOTATION_TYPE ? $::instance_conf->get_reqdate_interval       :
                   $self->type eq SALES_ORDER_TYPE     ? $::instance_conf->get_delivery_date_interval : 1;

  if (   ($self->type eq SALES_ORDER_TYPE     &&  $::instance_conf->get_deliverydate_on)
      || ($self->type eq SALES_QUOTATION_TYPE &&  $::instance_conf->get_reqdate_on)
      && (!$self->order->reqdate)) {
    $self->c->order->reqdate(DateTime->today_local->next_workday(extra_days => $extra_days));
  }
}

sub get_reqdate_by_type {
  my ($self, $reqdate, $saved_reqdate) = @_;

  if ($reqdate == $saved_reqdate) {
    my $extra_days = $self->type eq SALES_QUOTATION_TYPE ? $::instance_conf->get_reqdate_interval       :
                     $self->type eq SALES_ORDER_TYPE     ? $::instance_conf->get_delivery_date_interval : 1;

    if (   ($self->type eq SALES_ORDER_TYPE     &&  !$::instance_conf->get_deliverydate_on)
        || ($self->type eq SALES_QUOTATION_TYPE &&  !$::instance_conf->get_reqdate_on)) {
      return '';
    } else {
      return DateTime->today_local->next_workday(extra_days => $extra_days);
    }
  } else {
    return $reqdate;
  }
}
