//
// Block: Paste images when tweeting.
//
onAppReady.push(function supportImagePaste(){
  const uploader = $._data(document, "events")["uiComposeAddImageClick"][0].handler.context;
  
  app.delegate(".js-compose-text,.js-reply-tweetbox,.td-detect-image-paste", "paste", function(e){
    for(let item of e.originalEvent.clipboardData.items){
      if (item.type.startsWith("image/")){
        if (!$(this).closest(".rpl").find(".js-reply-popout").click().length){ // popout direct messages
          return if $(".js-add-image-button").is(".is-disabled"); // tweetdeck does not check upload count properly
        }
        
        uploader.addFilesToUpload([ item.getAsFile() ]);
        break;
      }
    }
  });
});

//
// Block: Allow changing first day of week in date picker.
//
if (checkPropertyExists($, "tools", "dateinput", "conf", "firstDay")){
  $.tools.dateinput.conf.firstDay = $TDX.firstDayOfWeek;
  
  onAppReady.push(function setupDatePickerFirstDayCallback(){
    window.TDGF_registerPropertyUpdateCallback(function($TDX){
      $.tools.dateinput.conf.firstDay = $TDX.firstDayOfWeek;
    });
  });
}

//
// Block: Override language used for translations.
//
if (checkPropertyExists(TD, "languages", "getSystemLanguageCode")){
  const prevFunc = TD.languages.getSystemLanguageCode;
  
  TD.languages.getSystemLanguageCode = function(returnShortCode){
    return returnShortCode ? ($TDX.translationTarget || "en") : prevFunc.apply(this, arguments);
  };
}

//
// Block: Add missing languages for Bing Translator (Bengali, Icelandic, Tagalog, Tamil, Telugu, Urdu).
//
execSafe(function addMissingTranslationLanguages(){
  ensurePropertyExists(TD, "languages", "getSupportedTranslationSourceLanguages");
  
  const newCodes = [ "bn", "is", "tl", "ta", "te", "ur" ];
  const codeSet = new Set(TD.languages.getSupportedTranslationSourceLanguages());
  
  for(const lang of newCodes){
    codeSet.add(lang);
  }
  
  const codeList = [...codeSet];
  
  TD.languages.getSupportedTranslationSourceLanguages = function(){
    return codeList;
  };
});

//
// Block: Bypass t.co when clicking/dragging links, media, and in user profiles.
//
execSafe(function setupShortenerBypass(){
  $(document.body).delegate("a[data-full-url]", "click auxclick", function(e){
    // event.which seems to be borked in auxclick
    // tweet links open directly in the column
    if ((e.button === 0 || e.button === 1) && $(this).attr("rel") !== "tweet"){
      $TD.openBrowser($(this).attr("data-full-url"));
      e.preventDefault();
    }
  });
  
  $(document.body).delegate("a[data-full-url]", "dragstart", function(e){
    const url = $(this).attr("data-full-url");
    const data = e.originalEvent.dataTransfer;
    
    data.clearData();
    data.setData("text/uri-list", url);
    data.setData("text/plain", url);
    data.setData("text/html", `<a href="${url}">${url}</a>`);
  });
  
  if (checkPropertyExists(TD, "services", "TwitterStatus", "prototype", "_generateHTMLText")){
    TD.services.TwitterStatus.prototype._generateHTMLText = prependToFunction(TD.services.TwitterStatus.prototype._generateHTMLText, function(){
      const card = this.card;
      const entities = this.entities;
      return if !(card && entities);
      
      const urls = entities.urls;
      return if !(urls && urls.length);
      
      const shortUrl = card.url;
      const urlObj = entities.urls.find(obj => obj.url === shortUrl && obj.expanded_url);
      
      if (urlObj){
        const expandedUrl = urlObj.expanded_url;
        card.url = expandedUrl;
        
        const values = card.binding_values;
        
        if (values && values.card_url){
          values.card_url.string_value = expandedUrl;
        }
      }
    });
  }
  
  if (checkPropertyExists(TD, "services", "TwitterMedia", "prototype", "fromMediaEntity")){
    const prevFunc = TD.services.TwitterMedia.prototype.fromMediaEntity;
    
    TD.services.TwitterMedia.prototype.fromMediaEntity = function(){
      const obj = prevFunc.apply(this, arguments);
      const e = arguments[0];
      
      if (e.expanded_url){
        if (obj.url === obj.shortUrl){
          obj.shortUrl = e.expanded_url;
        }
        
        obj.url = e.expanded_url;
      }
      
      return obj;
    };
  }
  
  if (checkPropertyExists(TD, "services", "TwitterUser", "prototype", "fromJSONObject")){
    const prevFunc = TD.services.TwitterUser.prototype.fromJSONObject;
    
    TD.services.TwitterUser.prototype.fromJSONObject = function(){
      const obj = prevFunc.apply(this, arguments);
      const e = arguments[0].entities;
      
      if (e && e.url && e.url.urls && e.url.urls.length && e.url.urls[0].expanded_url){
        obj.url = e.url.urls[0].expanded_url;
      }
      
      return obj;
    };
  }
});

//
// Block: Fix youtu.be previews not showing up for https links.
//
execSafe(function fixYouTubePreviews(){
  ensurePropertyExists(TD, "services", "TwitterMedia");
  
  const media = TD.services.TwitterMedia;
  
  ensurePropertyExists(media, "YOUTUBE_TINY_RE");
  ensurePropertyExists(media, "YOUTUBE_LONG_RE");
  ensurePropertyExists(media, "YOUTUBE_RE");
  ensurePropertyExists(media, "SERVICES", "youtube");
  
  media.YOUTUBE_TINY_RE = new RegExp(media.YOUTUBE_TINY_RE.source.replace("http:", "https?:"));
  media.YOUTUBE_RE = new RegExp(media.YOUTUBE_LONG_RE.source + "|" + media.YOUTUBE_TINY_RE.source);
  media.SERVICES["youtube"] = media.YOUTUBE_RE;
});

//
// Block: Refocus the textbox after switching accounts.
//
onAppReady.push(function setupAccountSwitchRefocus(){
  const refocusInput = function(){
    document.querySelector(".js-docked-compose .js-compose-text").focus();
  };
  
  const accountItemClickEvent = function(e){
    setTimeout(refocusInput, 0);
  };
  
  $(document).on("tduckOldComposerActive", function(e){
    $$(".js-account-list", ".js-docked-compose").delegate(".js-account-item", "click", accountItemClickEvent);
  });
});

//
// Block: Fix docked composer not re-focusing after Alt+Tab & image upload.
//
onAppReady.push(function fixDockedComposerRefocus(){
  $(document).on("tduckOldComposerActive", function(e){
    const ele = $$(".js-compose-text", ".js-docked-compose");
    const node = ele[0];
    
    let cancelBlur = false;
    
    ele.on("blur", function(e){
      cancelBlur = true;
      setTimeout(function(){ cancelBlur = false; }, 0);
    });
    
    window.TDGF_prioritizeNewestEvent(node, "blur");
    
    node.blur = prependToFunction(node.blur, function(){
      return cancelBlur;
    });
  });
  
  ensureEventExists(document, "uiComposeImageAdded");
  
  $(document).on("uiComposeImageAdded", function(){
    document.querySelector(".js-docked-compose .js-compose-text").focus();
  });
});

//
// Block: Fix DM reply input box not getting focused after opening a conversation.
//
if (checkPropertyExists(TD, "components", "ConversationDetailView", "prototype", "showChirp")){
  TD.components.ConversationDetailView.prototype.showChirp = appendToFunction(TD.components.ConversationDetailView.prototype.showChirp, function(){
    return if !$TDX.focusDmInput;
    
    setTimeout(function(){
      document.querySelector(".js-reply-tweetbox").focus();
    }, 100);
  });
}

//
// Block: Hold Shift to restore cleared column.
//
execSafe(function supportShiftToClearColumn(){
  ensurePropertyExists(TD, "vo", "Column", "prototype", "clear");
  
  let holdingShift = false;
  
  const updateShiftState = (pressed) => {
    if (pressed != holdingShift){
      holdingShift = pressed;
      $("button[data-action='clear']").children("span").text(holdingShift ? "Restore" : "Clear");
    }
  };
  
  const resetActiveFocus = () => {
    document.activeElement.blur();
  };
  
  document.addEventListener("keydown", function(e){
    if (e.shiftKey && (document.activeElement === null || !("value" in document.activeElement))){
      updateShiftState(true);
    }
  });
  
  document.addEventListener("keyup", function(e){
    if (!e.shiftKey){
      updateShiftState(false);
    }
  });
  
  TD.vo.Column.prototype.clear = prependToFunction(TD.vo.Column.prototype.clear, function(){
    window.setTimeout(resetActiveFocus, 0); // unfocuses the Clear button, otherwise it steals keyboard input
    
    if (holdingShift){
      this.model.setClearedTimestamp(0);
      this.reloadTweets();
      return true;
    }
  });
});

//
// Block: Make temporary search column appear as the first one and clear the input box.
//
execSafe(function setupSearchColumnHook(){
  ensurePropertyExists(TD, "controller", "columnManager", "_columnOrder");
  ensurePropertyExists(TD, "controller", "columnManager", "move");
  
  $(document).on("uiSearchNoTemporaryColumn", function(e, data){
    if (data.query && data.searchScope !== "users" && !data.columnKey){
      if ($TDX.openSearchInFirstColumn){
        const order = TD.controller.columnManager._columnOrder;
        
        if (order.length > 1){
          const columnKey = order[order.length - 1];
          
          order.splice(order.length - 1, 1);
          order.splice(1, 0, columnKey);
          TD.controller.columnManager.move(columnKey, "left");
        }
      }
      
      if (!("tduckResetInput" in data)){
        $(".js-app-search-input").val("");
        $(".js-perform-search").blur();
      }
    }
  });
});

//
// Block: Reorder search results to move accounts above hashtags.
//
onAppReady.push(function reorderSearchResults(){
  const container = $(".js-search-in-popover");
  const hashtags = $$(".js-typeahead-topic-list", container);
  
  $$(".js-typeahead-user-list", container).insertBefore(hashtags);
  hashtags.addClass("list-divider");
});

//
// Block: Revert Like/Follow dialogs being closed after clicking an action.
//
execSafe(function setupLikeFollowDialogRevert(){
  const prevSetTimeout = window.setTimeout;
  
  const overrideState = function(){
    return if !$TDX.keepLikeFollowDialogsOpen;
    
    window.setTimeout = function(func, timeout){
      return timeout !== 500 && prevSetTimeout.apply(this, arguments);
    };
  };
  
  const restoreState = function(context, key){
    window.setTimeout = prevSetTimeout;
    
    if ($TDX.keepLikeFollowDialogsOpen && key in context.state){
      context.state[key] = false;
    }
  };
  
  $(document).on("uiShowFavoriteFromOptions", function(){
    $(".js-btn-fav", ".js-modal-inner").each(function(){
      let event = $._data(this, "events").click[0];
      let handler = event.handler;
      
      event.handler = function(){
        overrideState();
        handler.apply(this, arguments);
        restoreState($._data(document, "events").dataFavoriteState[0].handler.context, "stopSubsequentLikes");
      };
    });
  });
  
  $(document).on("uiShowFollowFromOptions", function(){
    $(".js-component", ".js-modal-inner").each(function(){
      let event = $._data(this, "events").click[0];
      let handler = event.handler;
      let context = handler.context;
      
      event.handler = function(){
        overrideState();
        handler.apply(this, arguments);
        restoreState(context, "stopSubsequentFollows");
      };
    });
  });
});

//
// Block: Fix broken horizontal scrolling of column container when holding Shift.
//
if (checkPropertyExists(TD, "ui", "columns", "setupColumnScrollListeners")){
  TD.ui.columns.setupColumnScrollListeners = appendToFunction(TD.ui.columns.setupColumnScrollListeners, function(column){
    const ele = document.querySelector(".js-column[data-column='" + column.model.getKey() + "']");
    return if ele == null;
    
    $(ele).off("onmousewheel").on("mousewheel", ".scroll-v", function(e){
      e.stopImmediatePropagation();
    });
    
    window.TDGF_prioritizeNewestEvent(ele, "mousewheel");
  });
}

//
// Block: Fix DM image previews and GIF thumbnails not loading due to new URLs.
//
if (checkPropertyExists(TD, "services", "TwitterMedia", "prototype", "getTwitterPreviewUrl")){
  const prevFunc = TD.services.TwitterMedia.prototype.getTwitterPreviewUrl;
  
  TD.services.TwitterMedia.prototype.getTwitterPreviewUrl = function(){
    const url = prevFunc.apply(this, arguments);
    
    if (url.startsWith("https://ton.twitter.com/1.1/ton/data/dm/") || url.startsWith("https://pbs.twimg.com/tweet_video_thumb/")){
      const format = url.match(/\?.*format=(\w+)/);
      
      if (format && format.length === 2){
        const fix = `.${format[1]}?`;
        
        if (!url.includes(fix)){
          return url.replace("?", fix);
        }
      }
    }
    
    return url;
  };
}

//
// Block: Fix DMs not being marked as read when replying to them.
//
execSafe(function markRepliedDMsAsRead(){
  ensurePropertyExists(TD, "controller", "clients", "getClient");
  ensurePropertyExists(TD, "services", "Conversations", "prototype", "getConversation");
  
  $(document).on("dataDmSent", function(e, data){
    const client = TD.controller.clients.getClient(data.request.accountKey);
    return if !client;
    
    const conversation = client.conversations.getConversation(data.request.conversationId);
    return if !conversation;
    
    conversation.markAsRead();
  });
});

//
// Block: Limit amount of loaded DMs to avoid massive lag from re-opening them several times.
//
if (checkPropertyExists(TD, "services", "TwitterConversation", "prototype", "renderThread")){
  const prevFunc = TD.services.TwitterConversation.prototype.renderThread;
  
  TD.services.TwitterConversation.prototype.renderThread = function(){
    const prevMessages = this.messages;
    
    this.messages = prevMessages.slice(0, 100);
    const result = prevFunc.apply(this, arguments);
    this.messages = prevMessages;
    
    return result;
  };
}

//
// Block: Fix scheduled tweets not showing up sometimes.
//
execSafe(function fixScheduledTweets(){
  ensurePropertyExists(TD, "controller", "columnManager", "getAll");
  ensureEventExists(document, "dataTweetSent");
  
  $(document).on("dataTweetSent", function(e, data){
    if (data.response.state && data.response.state === "scheduled"){
      const column = Object.values(TD.controller.columnManager.getAll()).find(column => column.model.state.type === "scheduled");
      return if !column;
      
      setTimeout(function(){
        column.reloadTweets();
      }, 1000);
    }
  });
});

//
// Block: Let's make retweets lowercase again.
//
window.TDGF_injectMustache("status/tweet_single.mustache", "replace", "{{_i}} Retweeted{{/i}}", "{{_i}} retweeted{{/i}}");

if (checkPropertyExists(TD, "services", "TwitterActionRetweet", "prototype", "generateText")){
  TD.services.TwitterActionRetweet.prototype.generateText = appendToFunction(TD.services.TwitterActionRetweet.prototype.generateText, function(){
    this.text = this.text.replace(" Retweeted", " retweeted");
    this.htmlText = this.htmlText.replace(" Retweeted", " retweeted");
  });
}

if (checkPropertyExists(TD, "services", "TwitterActionRetweetedInteraction", "prototype", "generateText")){
  TD.services.TwitterActionRetweetedInteraction.prototype.generateText = appendToFunction(TD.services.TwitterActionRetweetedInteraction.prototype.generateText, function(){
    this.htmlText = this.htmlText.replace(" Retweeted", " retweeted").replace(" Retweet", " retweet");
  });
}