import { TAPi18n } from '/imports/i18n';
import { DatePicker } from '/client/lib/datepicker';
import { 
  formatDateTime, 
  formatDate, 
  formatDateByUserPreference,
  formatTime, 
  getISOWeek, 
  isValidDate, 
  isBefore, 
  isAfter, 
  isSame, 
  add, 
  subtract, 
  startOf, 
  endOf, 
  format, 
  parseDate, 
  now, 
  createDate, 
  fromNow, 
  calendar,
  diff
} from '/imports/lib/dateUtils';

// editCardReceivedDatePopup
(class extends DatePicker {
  onCreated() {
    super.onCreated(formatDateTime(now()));
    this.data().getReceived() &&
      this.date.set(new Date(this.data().getReceived()));
  }

  _storeDate(date) {
    this.card.setReceived(formatDateTime(date));
  }

  _deleteDate() {
    this.card.unsetReceived();
  }
}.register('editCardReceivedDatePopup'));

// editCardStartDatePopup
(class extends DatePicker {
  onCreated() {
    super.onCreated(formatDateTime(now()));
    this.data().getStart() && this.date.set(new Date(this.data().getStart()));
  }

  onRendered() {
    super.onRendered();
    // DatePicker base class handles initialization with native HTML inputs
  }

  _storeDate(date) {
    this.card.setStart(formatDateTime(date));
  }

  _deleteDate() {
    this.card.unsetStart();
  }
}.register('editCardStartDatePopup'));

// editCardDueDatePopup
(class extends DatePicker {
  onCreated() {
    super.onCreated('1970-01-01 17:00:00');
    this.data().getDue() && this.date.set(new Date(this.data().getDue()));
  }

  onRendered() {
    super.onRendered();
    // DatePicker base class handles initialization with native HTML inputs
  }

  _storeDate(date) {
    this.card.setDue(formatDateTime(date));
  }

  _deleteDate() {
    this.card.unsetDue();
  }
}.register('editCardDueDatePopup'));

// editCardEndDatePopup
(class extends DatePicker {
  onCreated() {
    super.onCreated(formatDateTime(now()));
    this.data().getEnd() && this.date.set(new Date(this.data().getEnd()));
  }

  onRendered() {
    super.onRendered();
    // DatePicker base class handles initialization with native HTML inputs
  }

  _storeDate(date) {
    this.card.setEnd(formatDateTime(date));
  }

  _deleteDate() {
    this.card.unsetEnd();
  }
}.register('editCardEndDatePopup'));

// Display received, start, due & end dates
const CardDate = BlazeComponent.extendComponent({
  template() {
    return 'dateBadge';
  },

  onCreated() {
    const self = this;
    self.date = ReactiveVar();
    self.now = ReactiveVar(now());
    window.setInterval(() => {
      self.now.set(now());
    }, 60000);
  },

  showWeek() {
    return getISOWeek(this.date.get()).toString();
  },

  showWeekOfYear() {
    const user = ReactiveCache.getCurrentUser();
    if (!user) {
      // For non-logged-in users, week of year is not shown
      return false;
    }
    return user.isShowWeekOfYear();
  },

  showDate() {
    const currentUser = ReactiveCache.getCurrentUser();
    const dateFormat = currentUser ? currentUser.getDateFormat() : 'YYYY-MM-DD';
    return formatDateByUserPreference(this.date.get(), dateFormat, true);
  },

  showISODate() {
    return this.date.get().toISOString();
  },
});

class CardReceivedDate extends CardDate {
  onCreated() {
    super.onCreated();
    const self = this;
    self.autorun(() => {
      self.date.set(new Date(self.data().getReceived()));
    });
  }

  classes() {
    let classes = 'received-date ';
    const dueAt = this.data().getDue();
    const endAt = this.data().getEnd();
    const startAt = this.data().getStart();
    const theDate = this.date.get();
    const now = this.now.get();
    
    // Received date logic: if received date is after start, due, or end dates, it's overdue
    if (
      (startAt && isAfter(theDate, startAt)) ||
      (endAt && isAfter(theDate, endAt)) ||
      (dueAt && isAfter(theDate, dueAt))
    ) {
      classes += 'overdue';
    } else {
      classes += 'not-due';
    }
    return classes;
  }

  showTitle() {
    const currentUser = ReactiveCache.getCurrentUser();
    const dateFormat = currentUser ? currentUser.getDateFormat() : 'YYYY-MM-DD';
    const formattedDate = formatDateByUserPreference(this.date.get(), dateFormat, true);
    return `${TAPi18n.__('card-received-on')} ${formattedDate}`;
  }

  events() {
    return super.events().concat({
      'click .js-edit-date': Popup.open('editCardReceivedDate'),
    });
  }
}
CardReceivedDate.register('cardReceivedDate');

class CardStartDate extends CardDate {
  onCreated() {
    super.onCreated();
    const self = this;
    self.autorun(() => {
      self.date.set(new Date(self.data().getStart()));
    });
  }

  classes() {
    let classes = 'start-date ';
    const dueAt = this.data().getDue();
    const endAt = this.data().getEnd();
    const theDate = this.date.get();
    const now = this.now.get();
    
    // Start date logic: if start date is after due or end dates, it's overdue
    if ((endAt && isAfter(theDate, endAt)) || (dueAt && isAfter(theDate, dueAt))) {
      classes += 'overdue';
    } else if (isAfter(theDate, now)) {
      // Start date is in the future - not due yet
      classes += 'not-due';
    } else {
      // Start date is today or in the past - current/active
      classes += 'current';
    }
    return classes;
  }

  showTitle() {
    const currentUser = ReactiveCache.getCurrentUser();
    const dateFormat = currentUser ? currentUser.getDateFormat() : 'YYYY-MM-DD';
    const formattedDate = formatDateByUserPreference(this.date.get(), dateFormat, true);
    return `${TAPi18n.__('card-start-on')} ${formattedDate}`;
  }

  events() {
    return super.events().concat({
      'click .js-edit-date': Popup.open('editCardStartDate'),
    });
  }
}
CardStartDate.register('cardStartDate');

class CardDueDate extends CardDate {
  onCreated() {
    super.onCreated();
    const self = this;
    self.autorun(() => {
      self.date.set(new Date(self.data().getDue()));
    });
  }

  classes() {
    let classes = 'due-date ';
    const endAt = this.data().getEnd();
    const theDate = this.date.get();
    const now = this.now.get();
    
    // If there's an end date and it's before the due date, task is completed early
    if (endAt && isBefore(endAt, theDate)) {
      classes += 'completed-early';
    }
    // If there's an end date, don't show due date status since task is completed
    else if (endAt) {
      classes += 'completed';
    }
    // Due date logic based on current time
    else {
      const daysDiff = diff(theDate, now, 'days');
      
      if (daysDiff < 0) {
        // Due date is in the past - overdue
        classes += 'overdue';
      } else if (daysDiff <= 1) {
        // Due today or tomorrow - due soon
        classes += 'due-soon';
      } else {
        // Due date is more than 1 day away - not due yet
        classes += 'not-due';
      }
    }
    
    return classes;
  }

  showTitle() {
    const currentUser = ReactiveCache.getCurrentUser();
    const dateFormat = currentUser ? currentUser.getDateFormat() : 'YYYY-MM-DD';
    const formattedDate = formatDateByUserPreference(this.date.get(), dateFormat, true);
    return `${TAPi18n.__('card-due-on')} ${formattedDate}`;
  }

  events() {
    return super.events().concat({
      'click .js-edit-date': Popup.open('editCardDueDate'),
    });
  }
}
CardDueDate.register('cardDueDate');

class CardEndDate extends CardDate {
  onCreated() {
    super.onCreated();
    const self = this;
    self.autorun(() => {
      self.date.set(new Date(self.data().getEnd()));
    });
  }

  classes() {
    let classes = 'end-date ';
    const dueAt = this.data().getDue();
    const theDate = this.date.get();
    
    if (!dueAt) {
      // No due date set - just show as completed
      classes += 'completed';
    } else if (isBefore(theDate, dueAt)) {
      // End date is before due date - completed early
      classes += 'completed-early';
    } else if (isAfter(theDate, dueAt)) {
      // End date is after due date - completed late
      classes += 'completed-late';
    } else {
      // End date equals due date - completed on time
      classes += 'completed-on-time';
    }
    return classes;
  }

  showTitle() {
    return `${TAPi18n.__('card-end-on')} ${format(this.date.get(), 'LLLL')}`;
  }

  events() {
    return super.events().concat({
      'click .js-edit-date': Popup.open('editCardEndDate'),
    });
  }
}
CardEndDate.register('cardEndDate');

class CardCustomFieldDate extends CardDate {
  template() {
    return 'dateCustomField';
  }

  onCreated() {
    super.onCreated();
    const self = this;
    self.autorun(() => {
      self.date.set(new Date(self.data().value));
    });
  }

  showWeek() {
    return getISOWeek(this.date.get()).toString();
  }

  showWeekOfYear() {
    const user = ReactiveCache.getCurrentUser();
    if (!user) {
      // For non-logged-in users, week of year is not shown
      return false;
    }
    return user.isShowWeekOfYear();
  }

  showDate() {
    // this will start working once mquandalle:moment
    // is updated to at least moment.js 2.10.5
    // until then, the date is displayed in the "L" format
    return this.date.get().calendar(null, {
      sameElse: 'llll',
    });
  }

  showTitle() {
    const currentUser = ReactiveCache.getCurrentUser();
    const dateFormat = currentUser ? currentUser.getDateFormat() : 'YYYY-MM-DD';
    const formattedDate = formatDateByUserPreference(this.date.get(), dateFormat, true);
    return `${formattedDate}`;
  }

  classes() {
    return 'customfield-date';
  }

  events() {
    return [];
  }
}
CardCustomFieldDate.register('cardCustomFieldDate');

(class extends CardReceivedDate {
  template() {
    return 'minicardReceivedDate';
  }
  
  showDate() {
    const currentUser = ReactiveCache.getCurrentUser();
    const dateFormat = currentUser ? currentUser.getDateFormat() : 'YYYY-MM-DD';
    return formatDateByUserPreference(this.date.get(), dateFormat, true);
  }
}.register('minicardReceivedDate'));

(class extends CardStartDate {
  template() {
    return 'minicardStartDate';
  }
  
  showDate() {
    const currentUser = ReactiveCache.getCurrentUser();
    const dateFormat = currentUser ? currentUser.getDateFormat() : 'YYYY-MM-DD';
    return formatDateByUserPreference(this.date.get(), dateFormat, true);
  }
}.register('minicardStartDate'));

(class extends CardDueDate {
  template() {
    return 'minicardDueDate';
  }
  
  showDate() {
    const currentUser = ReactiveCache.getCurrentUser();
    const dateFormat = currentUser ? currentUser.getDateFormat() : 'YYYY-MM-DD';
    return formatDateByUserPreference(this.date.get(), dateFormat, true);
  }
}.register('minicardDueDate'));

(class extends CardEndDate {
  template() {
    return 'minicardEndDate';
  }
  
  showDate() {
    const currentUser = ReactiveCache.getCurrentUser();
    const dateFormat = currentUser ? currentUser.getDateFormat() : 'YYYY-MM-DD';
    return formatDateByUserPreference(this.date.get(), dateFormat, true);
  }
}.register('minicardEndDate'));

(class extends CardCustomFieldDate {
  template() {
    return 'minicardCustomFieldDate';
  }
  
  showDate() {
    const currentUser = ReactiveCache.getCurrentUser();
    const dateFormat = currentUser ? currentUser.getDateFormat() : 'YYYY-MM-DD';
    return formatDateByUserPreference(this.date.get(), dateFormat, true);
  }
}.register('minicardCustomFieldDate'));

class VoteEndDate extends CardDate {
  onCreated() {
    super.onCreated();
    const self = this;
    self.autorun(() => {
      self.date.set(new Date(self.data().getVoteEnd()));
    });
  }
  classes() {
    const classes = 'end-date' + ' ';
    return classes;
  }
  showDate() {
    const currentUser = ReactiveCache.getCurrentUser();
    const dateFormat = currentUser ? currentUser.getDateFormat() : 'YYYY-MM-DD';
    return formatDateByUserPreference(this.date.get(), dateFormat, true);
  }
  showTitle() {
    return `${TAPi18n.__('card-end-on')} ${this.date.get().toLocaleString()}`;
  }

  events() {
    return super.events().concat({
      'click .js-edit-date': Popup.open('editVoteEndDate'),
    });
  }
}
VoteEndDate.register('voteEndDate');

class PokerEndDate extends CardDate {
  onCreated() {
    super.onCreated();
    const self = this;
    self.autorun(() => {
      self.date.set(new Date(self.data().getPokerEnd()));
    });
  }
  classes() {
    const classes = 'end-date' + ' ';
    return classes;
  }
  showDate() {
    const currentUser = ReactiveCache.getCurrentUser();
    const dateFormat = currentUser ? currentUser.getDateFormat() : 'YYYY-MM-DD';
    return formatDateByUserPreference(this.date.get(), dateFormat, true);
  }
  showTitle() {
    return `${TAPi18n.__('card-end-on')} ${format(this.date.get(), 'LLLL')}`;
  }

  events() {
    return super.events().concat({
      'click .js-edit-date': Popup.open('editPokerEndDate'),
    });
  }
}
PokerEndDate.register('pokerEndDate');
