import { IPermissionsModel } from '@fleio-api/base-model/IPermissionsModel';
import { IIcon } from '@shared/ui/common/interfaces/icon';
import { ITitle } from '@objects-view/interfaces/card-data/card-title';
import { IObjectStatus, StatusType, StatusValue } from '@objects-view/interfaces/object-status';
import { ObjectUIServiceBase } from '@objects-view/object-ui-service-base';
import { IAction } from '@objects-view/interfaces/actions/action';
import { RouterLinkAction } from '@objects-view/actions/router-link-action';
import { Router } from '@angular/router';
import { ConfigService } from '@shared/config/config.service';
import { IDataField } from '@objects-view/interfaces/card-data/data-field';
import { IInvoiceModel } from '@fleio-api/billing/model/invoice.model';
import { IDetailsTab } from '@objects-view/interfaces/details/details-tab';
import {
  InvoiceDetailsOverviewComponent
} from '@billing-invoices-tabs/invoice-details-overview/invoice-details-overview.component';
import { CallbackAction } from '@objects-view/actions/callback-action';
import { InvoicesApiService } from '@fleio-api/billing/invoices/invoices-api.service';
import { IClientModel } from '@fleio-api/client-user/model/client.model';
import { DateFormatterPipe } from '@shared/ui/common/pipes/date-formatter.pipe';
import { map } from 'rxjs/operators';
import { IActionResult } from '@objects-view/interfaces/actions/action-result';
import { MatDialog } from '@angular/material/dialog';
import { ApiCallAction } from '@objects-view/actions/api-call-action';
import { CurrencyFormatterPipe } from '@shared/ui/common/pipes/currency-formatter.pipe';
import { Observable } from 'rxjs';
import { EntityAuditLogComponent } from '../../common-components/entity-audit-log/entity-audit-log.component';
import {
  InvoiceDetailsAddPaymentComponent
} from './tabs/invoice-details-add-payment/invoice-details-add-payment.component';
import { InvoiceDetailsRefundComponent } from './tabs/invoice-details-refund/invoice-details-refund.component';
import { InvoiceEditFormComponent } from './tabs/invoice-edit-form/invoice-edit-form.component';
import {
  InvoiceSendNotificationDialogComponent
} from './dialogs/invoice-send-notification-dialog/invoice-send-notification-dialog.component';
import { InvoiceDeleteDialogComponent } from './dialogs/invoice-delete-dialog/invoice-delete-dialog.component';

export class InvoiceUIService extends ObjectUIServiceBase<IInvoiceModel> {
  private readonly router: Router;
  private readonly config: ConfigService;
  private readonly invoicesApi: InvoicesApiService;
  private readonly datePipe: DateFormatterPipe;
  private readonly matDialog: MatDialog;
  private currencyPipe: CurrencyFormatterPipe;

  constructor(
    invoice: IInvoiceModel, permissions: IPermissionsModel, state: string,
    router: Router, config: ConfigService, invoicesApi: InvoicesApiService, matDialog: MatDialog,
  ) {
    super(invoice, permissions, state);
    this.router = router;
    this.config = config;
    this.invoicesApi = invoicesApi;
    this.datePipe = new DateFormatterPipe(config);
    this.matDialog = matDialog;
    this.currencyPipe = new CurrencyFormatterPipe(this.config);
  }

  getIcon(): IIcon {
    return null;
  }

  getStatus(): IObjectStatus {
    let status: IObjectStatus = null;
    switch (this.object.status) {
      case 'paid':
        status = {type: StatusType.Defined, value: StatusValue.Paid};
        break;
      case 'canceled':
        status = {type: StatusType.Defined, value: StatusValue.Canceled};
        break;
      case 'refunded':
        status = {type: StatusType.Defined, value: StatusValue.Refunded};
        break;
      case 'unpaid':
        if (new Date(this.object.due_date).getTime() < new Date().getTime()) {
          status = {type: StatusType.Defined, value: StatusValue.Overdue};
        } else {
          status = {type: StatusType.Defined, value: StatusValue.Unpaid};
        }
        break;
    }

    if (['card-view', 'table-view', 'details'].includes(this.state)) {
      return status;
    }

    return null;
  }

  getTitle(): ITitle {
    switch (this.state) {
      case 'edit':
        return {
          text: $localize`Edit invoice ${this.object.display_number}`,
          subText: this.object.status.toLocaleUpperCase(),
        };
      case 'create':
        return {
          text: $localize`Create invoice`,
        };
      case 'details':
        return {
          text: this.object.name,
          subText: this.object.status.toLocaleUpperCase(),
        };
      default:
        return {
          text: `${this.object.display_number}`,
          subText: this.object.status.toLocaleUpperCase(),
        };
    }
  }

  getActions(): IAction[] {
    const actions: Array<IAction> = [];

    actions.push(
      new RouterLinkAction({
        icon: {name: 'edit'},
        name: $localize`Edit`,
        tooltip: $localize`Edit invoice`,
        routerUrl: this.config.getPanelUrl(`billing/invoices/${this.object.id}/edit`),
        router: this.router,
        noPermissions: !this.permissions['invoices.update'],
      })
    );

    actions.push(
      new CallbackAction(
        {
          object: this.object,
          tooltip: $localize`Send notification`,
          icon: {name: 'send'},
          name: $localize`Send notification`,
          callback: () => this.matDialog.open(
            InvoiceSendNotificationDialogComponent, {
              data: {invoiceID: this.object.id},
              autoFocus: false,
            }
          ).afterClosed().pipe(map(result => ({message: result} as IActionResult)))
        }
      )
    );

    if (!this.object.is_fiscal) {
      actions.push(new ApiCallAction(
        {
          object: this.object,
          icon: {name: 'receipt_long'},
          tooltip: $localize`Change to fiscal invoice`,
          name: $localize`Change to fiscal invoice`,
          confirmOptions: {
            confirm: true,
            title: $localize`Change to fiscal invoice`,
            message: $localize`Change proforma invoice to fiscal invoice? The fiscal invoice date will be set to the current date.`
          },
          apiService: this.invoicesApi,
          apiAction: 'change_to_fiscal_invoice',
          noPermissions: !this.permissions['invoices.change_to_fiscal_invoice'],
        }
      ));
    }

    actions.push(
      new CallbackAction(
        {
          object: this.object,
          tooltip: $localize`Delete`,
          icon: {name: 'delete'},
          name: $localize`Delete`,
          redirectAfterExecute: true,
          redirectUrl: this.config.getPanelUrl('billing/invoices'),
          noPermissions: !this.permissions['invoices.destroy'],
          callback: () => new Observable<IActionResult>((subscriber) => {
            this.matDialog.open(
              InvoiceDeleteDialogComponent, {
                data: {invoiceID: this.object.id},
                autoFocus: false,
              }).afterClosed().subscribe(result => {
              subscriber.next({success: !!result, message: null});
              subscriber.complete();
            });
          })
        }
      )
    );
    return actions;
  }

  getDetailsActions(): IAction[] {
    const actions = [];

    switch (this.state) {
      case 'create':
        actions.push(new RouterLinkAction({
            name: $localize`Cancel`,
            routerUrl: this.config.getPrevUrl(`billing/invoices`),
            router: this.router,
          }
        ));
        actions.push(new CallbackAction({name: $localize`Create invoice`}));
        break;
      case 'edit':
        actions.push(new RouterLinkAction({
            name: $localize`Cancel`,
            routerUrl: this.config.getPrevUrl(`billing/invoices`),
            router: this.router,
          }
        ));
        actions.push(new CallbackAction({name: $localize`Save invoice`}));
        break;
      default:
        break;
    }

    return actions;
  }

  getCardTags(): string[] {
    return [];
  }

  getDetailsLink(): string {
    return this.config.getPanelUrl(`billing/invoices/${this.object.id}`);
  }

  getCardFields(): IDataField[] {
    return [
      {
        name: $localize`Issue date`,
        value: this.datePipe.transform(this.object.issue_date),
        title: this.datePipe.getTitleAttributeValue(this.object.issue_date)
      },
      {
        name: $localize`Total`,
        value: this.currencyPipe.transform(this.object.total, this.object.currency, this.config.authService.currencyDisplayMode, null)
      },
      {
        name: $localize`Client`,
        value: this.object.client ? (this.object.client as IClientModel).display : $localize`n/a`,
      }
    ];
  }

  getTabs(): IDetailsTab[] {
    switch (this.state) {
      case 'details':
        return [
          {
            tabName: $localize`Details`,
            tabIdentifier: 'details',
            component: InvoiceDetailsOverviewComponent,
          },
          {
            tabName: $localize`Add payment`,
            tabIdentifier: 'add-payment',
            component: InvoiceDetailsAddPaymentComponent,
          },
          {
            tabName: $localize`Refund`,
            tabIdentifier: 'refund',
            component: InvoiceDetailsRefundComponent,
          },
          {
            tabName: $localize`Audit log`,
            tabIdentifier: 'audit-log',
            component: EntityAuditLogComponent,
            featureName: 'utils.activitylog',
            data: {
              entity_type: 'invoice'
            }
          }
        ];
      case 'edit':
      case 'create':
        return [
          {
            tabName: $localize`Edit`,
            tabIdentifier: 'edit',
            component: InvoiceEditFormComponent,
          }
        ];
      default:
        return null;
    }
  }
}
