import { Injectable } from '@angular/core';
import { Router } from '@angular/router';

import { MatDialog } from '@angular/material/dialog';
import { IObjectListUIService } from '@objects-view/interfaces/object-list-ui-service';
import { ConfigService } from '@shared/config/config.service';
import { TicketsApiService } from '@fleio-api/plugins/tickets/tickets-api.service';
import { IBaseFleioObjectModel } from '@fleio-api/base-model/base-fleio-object.model';
import { IPermissionsModel } from '@fleio-api/base-model/IPermissionsModel';
import { IObjectUIService } from '@objects-view/interfaces/object-ui-service';
import { TicketUiService } from './ticket-ui.service';
import { ITicketModel } from '@fleio-api/plugins/tickets/model/ticket.model';
import { FleioObjectsList } from '@fleio-api/fleio-objects-list';
import { ITableData } from '@objects-view/interfaces/table-data/table-data';
import { ColumnType } from '@objects-view/interfaces/table-data/column-definition';
import { ITableRow } from '@objects-view/interfaces/table-data/table-row';
import { IAction } from '@objects-view/interfaces/actions/action';
import { RouterLinkAction } from '@objects-view/actions/router-link-action';
import { TicketsUtilsService } from '@fleio-api/plugins/tickets/tickets-utils.service';
import { AppColor } from '@shared/ui/common/enums/app-color.enum';
import { IIcon } from '@shared/ui/common/interfaces/icon';
import { StatusType, StatusValue } from '@objects-view/interfaces/object-status';
import { AppLocalStorageService } from '@shared/ui-api/app-local-storage.service';
import { TicketRowType } from './ticket-row-type.enum';
import { RefreshService } from '@shared/ui-api/refresh.service';

@Injectable({
  providedIn: 'root',
})
export class TicketsListUiService implements IObjectListUIService {
  public noItemsMessage = $localize`No tickets`;
  private readonly ticketsUtilsService: TicketsUtilsService;

  constructor(
    private router: Router, private config: ConfigService,
    private ticketsApiService: TicketsApiService,
    private matDialog: MatDialog,
    private appLocalStorageService: AppLocalStorageService,
    private refreshService: RefreshService,
  ) {
    this.ticketsUtilsService = new TicketsUtilsService();
  }

  getObjectUIService(
    object: IBaseFleioObjectModel, permissions: IPermissionsModel, state: string
  ): IObjectUIService {
    return new TicketUiService(
      object as ITicketModel, permissions, state, this.router, this.config, this.ticketsApiService,
      this.matDialog, this.refreshService,
    );
  }

  getTableData(objectList: FleioObjectsList<ITicketModel>): ITableData {
    let defaultExpandedRows = this.appLocalStorageService.getTicketListExpandedRows();
    if (!defaultExpandedRows) {
      defaultExpandedRows = {};
      defaultExpandedRows[TicketRowType.PinnedByMe] = true;
    }
    const tableData: ITableData = {
      header: {
        columns: [
          {
            type: ColumnType.Value, displayName: $localize`Subject`, enableSort: true, fieldName: 'subject',
            flex: '35%', flexXs: '65%', displayAsHtml: true,
          },
          {
            type: ColumnType.Value, displayName: $localize`Client name`, enableSort: false, fieldName: 'client_name',
            flex: '20%', flexXs: '30%',
          },
          {
            type: ColumnType.Value, displayName: $localize`Last reply`, enableSort: true, fieldName: 'last_reply_at',
            flex: '8.33%', hide: {xs: true, sm: true},
          },
          {
            type: ColumnType.Value, displayName: $localize`Department`, enableSort: true, fieldName: 'department',
            flex: '13.33%', hide: {xs: true},
          },
          {
            type: ColumnType.Value, displayName: $localize`Status`, enableSort: true, fieldName: 'status',
            flex: '8.33%', hide: {xs: true, sm: true, md: true},
          },
          {
            type: ColumnType.Actions, displayName: $localize`Actions`, enableSort: false, fieldName: '(actions)',
          },
        ],
        columnNames: [
          'subject', 'client_name', 'last_reply_at', 'department', 'status', '(actions)'
        ],
        showStatus: true,
        visibleActions: 1,
      },
      defaultExpandedRows,
      rows: [],
    };

    let separateCollapsibleRowTop = true;
    const pushedPinnedByMeRow = this.pushCollapsibleRow(
      tableData, objectList, TicketRowType.PinnedByMe, separateCollapsibleRowTop,
    );
    separateCollapsibleRowTop = !pushedPinnedByMeRow;
    const pushedPinnedByOthersRow = this.pushCollapsibleRow(
      tableData, objectList, TicketRowType.PinnedByOthers, separateCollapsibleRowTop,
    );

    // do not separate normal list if there is no pinned row
    let separateTop = pushedPinnedByMeRow || pushedPinnedByOthersRow;
    for (const ticket of objectList.objects) {
      this.pushTicketRow(tableData, ticket, objectList, null, separateTop);
      separateTop = false;  // separate normal list just once, for the first item
    }

    return tableData;
  }

  private pushCollapsibleRow(tableData, objectList, rowType: TicketRowType = null, separateTop = false): boolean {
    let pinnedRowTitle: string;
    let pinnedCount: number;
    let pinnedTickets;
    switch (rowType) {
      case TicketRowType.PinnedByMe:
        pinnedTickets = (objectList as any).pinned_tickets_by_me;
        pinnedCount = pinnedTickets.length;
        if (pinnedCount === 0) {
          // do not push any collapsible row in this case
          return false;
        }
        if (pinnedCount > 1) {
          pinnedRowTitle = $localize`${pinnedCount} pinned tickets by me`;
        } else {
          pinnedRowTitle = $localize`${pinnedCount} pinned ticket by me`;
        }
        break;
      case TicketRowType.PinnedByOthers:
        pinnedTickets = (objectList as any).pinned_tickets_by_others;
        pinnedCount = pinnedTickets.length;
        if (pinnedCount === 0) {
          // do not push any collapsible row in this case
          return;
        }
        if (pinnedCount > 1) {
          pinnedRowTitle = $localize`${pinnedCount} pinned tickets by other staff members`;
        } else {
          pinnedRowTitle = $localize`${pinnedCount} pinned ticket by other staff members`;
        }
        break;
    }
    const pinnedRow: ITableRow = {
      cells: {
        subject: {
          text: pinnedRowTitle,
          textBold: true,
        },
        client_name: {text: null},
        last_reply_at: {text: null},
        department: {text: null},
        assigned_user: {text: null},
        status: {text: null},
      },
      status: {type: StatusType.None, value: StatusValue.None},
      expandable: true,
      showsRows: rowType,
      separateTop,
      hideBoxShadow: true,
      object: {id: rowType},
    };

    tableData.rows.push(pinnedRow);

    for (const ticket of pinnedTickets) {
      this.pushTicketRow(tableData, ticket, objectList, rowType);
    }
    return true;
  }

  private pushTicketRow(
    tableData, ticket: ITicketModel, objectList, rowType: TicketRowType = null, separateTop=false
  ) {
    const rowUIService = this.getObjectUIService(ticket, objectList.permissions, 'table-view');
    let statusColor: AppColor;
    if (ticket.status === 'answered') {
      statusColor = AppColor.Green;
    } else if (ticket.status === 'in progress') {
      statusColor = AppColor.Red;
    } else if (ticket.status === 'on hold' || ticket.status === 'customer reply' || ticket.status === 'open') {
      statusColor = AppColor.Orange;
    } else if (ticket.status === 'done') {
      statusColor = AppColor.Gray;
    }
    const lastReplyAt = this.ticketsUtilsService.formatLastReply(ticket.last_reply_at, this.config.locale);
    const lastReplyDate = ticket.last_reply_at ? new Date(ticket.last_reply_at) : null;
    const lastReplyTitle = lastReplyDate ? $localize`${lastReplyDate.toDateString()} ${lastReplyDate.toTimeString()}` : null;

    const totalPinnedByCount = ticket.users_that_pinned_this.length;
    let usersThatPinnedThisDisplay = null;
    const usersThatPinnedThis = ticket.users_that_pinned_this;
    if (totalPinnedByCount) {
      if (totalPinnedByCount > 1) {
        const lastUser = usersThatPinnedThis.pop();
        usersThatPinnedThisDisplay = $localize`Pinned by ${usersThatPinnedThis.join(', ')} and ${lastUser}`;
      } else {
        usersThatPinnedThisDisplay = $localize`Pinned by ${usersThatPinnedThis[0]}`;
      }
    }
    const row: ITableRow = {
      cells: {
        subject: {
          text: ticket.title,
          subText: `#${ticket.id}`,
          subTextTitle: usersThatPinnedThisDisplay,
          textIcon: ticket.users_that_pinned_this.length ? {
            name: 'push_pin',
            fontSize: '14px',
            title: usersThatPinnedThisDisplay,
            width: '15px',
            height: '15px',
            verticalAlign: 'middle',
          } as IIcon : null,
          paddingLeft: rowType ? '12px' : null,
        },
        client_name: {text: ticket.client ? ticket.client_display : ticket.opener_email},
        last_reply_at: {
          text: lastReplyAt,
          title: lastReplyTitle
        },
        department: {
          text: ticket.department_display,
          subText: ticket.assigned_to ? $localize`assigned to ${ticket.assigned_to_display}` : '',
        },
        status: {text: ticket.status_display, textColor: statusColor, textBold: true},
      },
      icon: rowUIService.getIcon(),
      status: rowUIService.getStatus({rowType}),
      actions: rowUIService.getActions(),
      url: rowUIService.getDetailsLink(),
      boldText: ticket.unread,
      rowType,
      separateTop,
      object: ticket,
    };
    tableData.trackByFunction = (index, item: ITableRow) => item.object.id;
    tableData.rows.push(row);
  }

  getActions(objectList: FleioObjectsList<IBaseFleioObjectModel>): IAction[] {
    return [
      new RouterLinkAction({
        name: $localize`Open a new ticket`,
        tooltip: $localize`Open a new ticket`,
        icon: {name: 'add'},
        router: this.router,
        routerUrl: this.config.getPanelUrl('tickets/open-new-ticket')
      })
    ];
  }

  getRefreshInterval(): number {
    return this.config.getDefaultRefreshInterval();
  }
}
