import { animation_default, capsule_bar_height, click_effect_default, fontSize_Large } from '../../hosts/bunch_of_defaults';
import { bunch_of_history, history_record } from '../../hosts/bunch_of_history';
import { bunch_of_tabs, tab_label } from '../../hosts/bunch_of_tabs';
import { sandbox_save } from '../../utils/storage_tools';
import { match_domain, url_meow_to_resource, url_resource_to_meow, viewable_domains } from '../../utils/url_tools';
import { webview } from '@kit.ArkWeb';
import { bunch_of_settings } from '../../hosts/bunch_of_settings';
import woofWantDownload from '../../dialogs/prompts/woofWantDownload';
import { bookmark, bunch_of_bookmarks, folder, unified_item } from '../../hosts/bunch_of_bookmarks';
import woofWantJump from '../../dialogs/prompts/woofWantJump';
import { bunch_of_downloads } from '../../hosts/bunch_of_downloads';
import woofWantResources from '../../dialogs/prompts/woofWantProtectedResources';
import { BusinessError, print } from '@kit.BasicServicesKit';
import { print_web } from '../../utils/print_tools';
import { Want } from '@kit.AbilityKit';
import { meowContext } from '../../utils/environment_tools';

@Component
struct meowWebView {
  @StorageProp('currentColorMode') current_color_mode: number = 0;
  @StorageProp('pathDir') pathDir: string = "";
  @StorageProp('tablet_mode') tablet_mode: boolean = false;
  @StorageLink('fullscreen_mode') fullscreen_mode: boolean = false;
  @StorageLink('fullscreen_handler') handler: FullScreenExitHandler | null = null;
  @StorageLink('restore_web_state_arrays') restore_web_state_arrays: Uint8Array[] = [];
  @StorageLink('bunch_of_tabs') bunch_of_tabs: bunch_of_tabs = new bunch_of_tabs(true);
  @StorageLink('bunch_of_history') bunch_of_history: bunch_of_history = new bunch_of_history(true);
  @StorageLink('bunch_of_bookmarks') @Watch('refresh_homepage_shortcuts') bunch_of_bookmarks: bunch_of_bookmarks = new bunch_of_bookmarks('Bookmarks~Meow');
  @StorageLink('bunch_of_settings') bunch_of_settings: bunch_of_settings = new bunch_of_settings(true);
  @StorageLink('bunch_of_downloads') bunch_of_downloads: bunch_of_downloads = new bunch_of_downloads();
  @StorageLink('current_main_tab_index') @Watch('on_tab_info_change') current_main_tab_index: number = 0;
  @StorageLink('current_sub_tab_index') @Watch('on_tab_info_change') current_sub_tab_index: number = -1;
  @StorageLink('homepage_background') homepage_background: PixelMap | undefined = undefined;
  @StorageProp('screen_height') screen_height: number = 100;
  // Controls and environments
  @StorageLink('tab_titles') tab_titles: string[] = []
  @StorageLink('current_title') current_title: string = "=￣ω￣=";
  @StorageLink('tab_urls') tab_urls: string[] = []
  @StorageLink('current_url') current_url: string = "=￣ω￣=";
  @StorageLink('tab_loading_progresses') tab_loading_progresses: number[] = [0]
  @StorageLink('current_loading_progress') current_loading_progress: number = 0
  @StorageLink('tab_is_loading') tab_is_loading: boolean[] = [true]
  @StorageLink('current_is_loading') current_is_loading: boolean = true
  @StorageLink('current_in_page_searching_stats_current') current_in_page_searching_stats_current: number = 0;
  @StorageLink('current_in_page_searching_stats_total') current_in_page_searching_stats_total: number = 0;
  @StorageLink('current_in_page_searching_keyword') current_in_page_searching_keyword: string = ''
  // Web control statuses
  @StorageLink('current_accessForward') current_accessForward: boolean = false;
  @StorageLink('current_accessBackward') current_accessBackward: boolean = false;
  @StorageLink('search_input') search_input: string = "*(੭*ˊᵕˋ)੭*ଘ";
  @StorageLink('search_input_source') search_input_update_source: string = "web";
  @StorageLink('is_search_input_typing') is_search_input_typing: boolean = false;
  // Settings
  @StorageProp('collect_new_history') collect_new_history: boolean = true;
  @StorageProp('intelligent_tracking_prevention') intelligent_tracking_prevention: boolean = false;
  @StorageLink('use_adblock') @Watch('on_use_adblock_state_change') use_adblock: boolean = true;
  @StorageLink('homepage_shortcuts_bookmarks_dir') @Watch('refresh_homepage_shortcuts') homepage_shortcuts_dir: string = '/';
  @StorageLink('homepage_shortcuts_init_height') homepage_shortcuts_init_height: number = 50;
  @StorageLink('web_force_dark_mode') web_force_dark_mode: boolean = false;
  @StorageLink('disable_js') disable_js: boolean = false;
  @StorageLink('disable_js_these_sites') disable_js_these_sites: string[] = [];
  @StorageLink('disable_js_all_sites') disable_js_all_sites: boolean = true;
  @StorageLink('disable_image') disable_image: boolean = false;
  @StorageLink('disable_image_these_sites') disable_image_these_sites: string[] = [];
  @StorageLink('disable_image_all_sites') disable_image_all_sites: boolean = true;
  // Settings - Accessibility
  @StorageLink('preferred_hand_left_or_right') preferred_hand_left_or_right: string = 'right';
  @StorageLink('preferred_hand_reverse_homepage_shortcuts') preferred_hand_reverse_homepage_shortcuts: boolean = false;
  // Stuffs
  @StorageLink('universal_new_tab_gateway') new_tab_gateway: string = "";
  @StorageLink('universal_global_custom_ua_gateway') now_global_custom_UA: string = "";
  @StorageLink('universal_new_download_filename_gateway') new_download_filename_gateway: string = "";
  @StorageLink('universal_new_download_additional_info') new_download_additional_info: string = "";
  @StorageLink('universal_new_download_gateway') new_download_gateway: string = "";
  // Visual
  @StorageProp('tab_animation') tab_animation: AnimateParam = animation_default();
  @State last_timeout_id: number | undefined = undefined;
  @State shortcut_scroll_offset: number = 0;
  @State shortcut_scroll_total_height: number = 100;
  @State homepage_shortcuts: unified_item[] = [];
  @State potential_jump_link: string = '';
  @StorageLink('extra_background') extra_background: boolean = false;
  // Download
  @StorageLink('dl_delegate') dl_delegate: webview.WebDownloadDelegate = new webview.WebDownloadDelegate();
  @StorageLink('blob_delegate') blob_delegate: webview.WebDownloadDelegate = new webview.WebDownloadDelegate();
  @StorageLink('dl_controller') dl_controller: webview.WebviewController = new webview.WebviewController();
  @StorageLink('print_adapter') print_adapter: print.PrintDocumentAdapter | undefined = undefined;
  // dialogs
  woofWantDownload_control: CustomDialogController = new CustomDialogController({
    builder: woofWantDownload({
      from: this.current_url,
      file_name: '',
      url: '',
      try_additional_info: ''
    }),
    alignment: DialogAlignment.Center,
    cornerRadius: 16
  })
  woofLinkJumper_control: CustomDialogController = new CustomDialogController({
    builder: woofWantJump({
      link: this.potential_jump_link,
    }),
    alignment: DialogAlignment.Center,
    cornerRadius: 16
  })
  onPermit?: () => void;
  onDeny?: () => void;
  ask_resources: string[] = [];
  source: string = '';
  woofWantProtectedResources_control: CustomDialogController = new CustomDialogController({
    builder: woofWantResources({
      protected_resource_types: this.ask_resources,
      onPermit: this.onPermit,
      onDeny: this.onDeny,
      source: this.source
    }),
    alignment: DialogAlignment.Center,
    cornerRadius: 16
  })

  // Colors
  @StorageProp('color_current_secondary') color_current_secondary: ResourceColor = $r('app.color.block_color');
  // Else
  @StorageLink('meowWebView_init_OK') init_OK: boolean = false;
  adsBlocker_exceptions: string[] = [];
  shortcut_scroller: Scroller = new Scroller();
  httpAuth: boolean = false;


  async aboutToAppear(): Promise<void> {
    let sites_got: string;

    try {
      // Get whether image is disabled
      this.disable_image = await this.bunch_of_settings.get('disable_image') as boolean;
      this.disable_image_all_sites = await this.bunch_of_settings.get('disable_image_all_sites') as boolean;

      // Get image ban specifications
      sites_got = await this.bunch_of_settings.get('disable_image_these_sites') as string;
      if (sites_got == '') {
        this.disable_image_these_sites = [];
      } else {
        this.disable_image_these_sites = sites_got.split('\n');
      }
    } catch (e) {
      console.error(e);
    }

    try {
      // Get whether js is disabled
      this.disable_js = await this.bunch_of_settings.get('disable_js') as boolean;
      this.disable_js_all_sites = await this.bunch_of_settings.get('disable_js_all_sites') as boolean;

      // Get js ban specifications
      sites_got = await this.bunch_of_settings.get('disable_js_these_sites') as string;
      if (sites_got == '') {
        this.disable_js_these_sites = [];
      } else {
        this.disable_js_these_sites = sites_got.split('\n');
      }

    } catch (e) {
      console.error(e);
    }

    try {
      // Get whether ads blocker is enabled
      this.use_adblock = await this.bunch_of_settings.get('use_adblock') as boolean;

      // Get adblock exceptions
      let got_adsBlocker_exceptions = await this.bunch_of_settings.get('adblock_exceptions') as string;
      this.adsBlocker_exceptions = [];
      if (got_adsBlocker_exceptions == '') {
        this.adsBlocker_exceptions = [];
      } else {
        this.adsBlocker_exceptions = got_adsBlocker_exceptions.split('\n');
      }
      // Sync to AppStorage
      AppStorage.set('adblock_exceptions', this.adsBlocker_exceptions);

      // Get homepage shortcuts height
      this.homepage_shortcuts_init_height = await this.bunch_of_settings.get('homepage_shortcuts_init_height') as number;

    } catch (e) {
      console.error(e);
    }

    // try {
    //   let atManager = abilityAccessCtrl.createAtManager();
    //   atManager.requestPermissionsFromUser(this.getUIContext().getHostContext(), ['ohos.permission.CAMERA', 'ohos.permission.MICROPHONE'])
    //     .then((data) => {
    //       console.info('data:' + JSON.stringify(data));
    //       console.info('data permissions:' + data.permissions);
    //       console.info('data authResults:' + data.authResults);
    //     }).catch((error: BusinessError) => {
    //     console.error(`Failed to request permissions from user. Code is ${error.code}, message is ${error.message}`);
    //   })
    // } catch (e) {
    //   console.error(e);
    // }

    // init OK
    setTimeout(() => {
      this.init_OK = true;
      // console.log('qwq')
    }, 10)
  }

  build() {
    RelativeContainer() {

      Row() // Background color
        .backgroundColor(this.current_color_mode == 0 ? (this.web_force_dark_mode ? 'black' : 'white') : 'white')
        .height('100%')
        .width('100%')
        .visibility(this.extra_background ? Visibility.Visible : Visibility.Hidden)
      // .animation(animation_default())

      // Specific web to handle downloads
      Web({ src: $rawfile('home.html'), controller: this.dl_controller })
        .onPageEnd(() => {
          try {
            // Bind delegate at init
            this.dl_controller.setDownloadDelegate(this.dl_delegate);
          } catch (e) {
            console.error(e);
          }
        })
        // .opacity(0.2)
        .visibility(Visibility.Hidden)


      // 为每一个标签创建一个web视图
      ForEach(this.bunch_of_tabs.Labels, (Label: tab_label) => {
        Column() {
          Web({
            src: this.src_of_tab_index(Label.index_key),
            controller: this.bunch_of_tabs.Tabs[Label.index_key] !== undefined
              ? this.bunch_of_tabs.Tabs[Label.index_key].controller
              : undefined,
            // renderMode: RenderMode.SYNC_RENDER
          })// Main WEB
            .width("100%")
            .height("100%")
            .backgroundColor('transparent')
            .darkMode(this.web_force_dark_mode ? WebDarkMode.On : WebDarkMode.Off)
            .databaseAccess(true)
            .javaScriptAccess(this.my_js(Label.index_key))
            .imageAccess(this.my_image(Label.index_key))
            .onlineImageAccess(this.my_image(Label.index_key))
            .fileAccess(true)
            .domStorageAccess(true)
            .multiWindowAccess(true)
            .mixedMode(MixedMode.All)
            .allowWindowOpenMethod(true)
            .onSearchResultReceive((result) => {
              this.current_in_page_searching_stats_current =
                Math.min(result.numberOfMatches, result.activeMatchOrdinal + 1);
              this.current_in_page_searching_stats_total = result.numberOfMatches;
              this.bunch_of_tabs.workingMainTab().searching_keyword_stats_current =
                Math.min(result.numberOfMatches, result.activeMatchOrdinal + 1);
              this.bunch_of_tabs.workingMainTab().searching_keyword_stats_total = result.numberOfMatches;
            })
            .onWindowNew((event) => {
              // TODO: Find out why this triggers twice when click once
              let new_target_url = event.targetUrl;
              console.log('[meowWebView] New tab in new window!')
              this.new_tab_gateway = new_target_url;
              event.handler.setWebController(null);
            })
            .onErrorReceive((e) => {
              if (e) {
                console.error("[ArkWeb][ERROR] " + e.error.getErrorCode() + ", " + e.error.getErrorInfo()
                  + " @ " + this.tab_urls[Label.index_key])
                // Log web errors
              }
            })
            .onPageBegin(() => {
              console.log("[Meow][ArkWeb] on page begin");

              // bind blob download delegate
              this.bunch_of_downloads.init_blob_delegate();
              this.bunch_of_tabs.Tabs[Label.index_key].controller.setDownloadDelegate(this.blob_delegate);

              if (Label.index_key >= this.bunch_of_tabs.get_tabs_count()) {
                // If not synced, idk why but o(=•ェ•=)m
                return;
              }

              // Update History
              this.current_accessBackward = this.bunch_of_tabs.Tabs[Label.index_key].controller.accessBackward()
              this.current_accessForward = this.bunch_of_tabs.Tabs[Label.index_key].controller.accessForward()
              // Ask tab to update its info (Reset)
              this.bunch_of_tabs.Tabs[Label.index_key].update_title()
              this.bunch_of_tabs.Tabs[Label.index_key].update_url()
              this.bunch_of_tabs.Tabs[Label.index_key].update_is_loading(true)
              this.bunch_of_tabs.Tabs[Label.index_key].update_loading_progress(0)
              // Get synced lists
              this.sync_list_info()
              // Update Input Search Box
              this.update_current_info()
              this.update_search_box_text(this.current_url)

            })
            .onPageEnd(() => {
              // console.log("[Meow][ArkWeb] on page end")
              this.bunch_of_tabs.Tabs[Label.index_key].update_title();
              this.bunch_of_tabs.Tabs[Label.index_key].update_url();
              this.bunch_of_tabs.Tabs[Label.index_key].update_is_loading(false);
              this.tab_is_loading = this.bunch_of_tabs.get_all_is_loading();
              this.update_current_info();

              // Save browse history if is neither resource tab nor a recovery tab
              if (this.collect_new_history
                && !this.bunch_of_tabs.Tabs[Label.index_key].restore_on_creation
                && !this.tab_urls[Label.index_key].includes("resource://")
              ) {
                let new_record = new history_record(this.tab_titles[Label.index_key], this.tab_urls[Label.index_key])
                this.bunch_of_history.add_history(new_record, true, true);
              } else {
                this.bunch_of_tabs.Tabs[Label.index_key].restore_on_creation = false;
                // log
                if (!this.collect_new_history) {
                  console.log("[meowWebView] Didn't save history for settings disabled.");
                } else {
                  console.log("[meowWebView] Didn't save history for a recovery process in progress");
                }
              }

              this.determine_extra_background();
            })
            .onProgressChange((event) => {
              if (!event) {
                return;
              }

              let progress: number = event.newProgress;
              // console.log("[Meow][ArkWeb] on progress change: " + progress.toString())
              // Update current loading progress
              if (progress == 0) {
                return;
              }

              if (Label.index_key >= this.bunch_of_tabs.get_tabs_count()) {
                // If not synced, idk why but o(=•ェ•=)m
                return;
              }

              this.bunch_of_tabs.Tabs[Label.index_key].update_title()
              this.bunch_of_tabs.Tabs[Label.index_key].update_url()
              this.bunch_of_tabs.Tabs[Label.index_key].update_loading_progress(progress)
              // Ask tab to update its info
              this.sync_list_info()
              // Get synced lists
              this.update_current_info()
              // Update Input Search Box
              this.update_search_box_text(this.current_url)

              if (this.bunch_of_tabs.Tabs[Label.index_key].restore_on_creation) {
                return;
              }

              // Get web_state
              let web_state = this.bunch_of_tabs.Tabs[Label.index_key].controller.serializeWebState();
              // Sync to bunch_of_tabs
              this.bunch_of_tabs.Tabs[Label.index_key].web_state_array = web_state;
              // save web state to sandbox storage
              if (web_state && !this.bunch_of_tabs.Tabs[Label.index_key].restore_on_creation) {
                let identifier = "continue/continue_tabs_web_state_array_" + Label.index_key.toString();
                sandbox_save(identifier, web_state.buffer);
              }
            })
            .onDownloadStart((event) => {
              this.download_event(event);
            })
            .onFullScreenEnter((event) => {
              this.fullscreen_mode = true;
              this.handler = event.handler;
            })
            .onFullScreenExit(() => {
              this.fullscreen_mode = false;
            })
            .onControllerAttached(async () => {
              // Set UA
              if (this.now_global_custom_UA != "") {
                this.bunch_of_tabs.Tabs[Label.index_key].controller.setCustomUserAgent(this.now_global_custom_UA);
              }

              // Set Ads Blocker
              console.log('[Meow][meowWebView] enableAdsBlock: ' + (this.use_adblock ? 'true' : 'false'))
              this.bunch_of_tabs.Tabs[Label.index_key].controller.enableAdsBlock(this.use_adblock);

              // TODO: Find out why this doesn't work sometimes for a recovered webpage :O getting crazy
              // Set Ads Blocker exception list
              try {
                console.log('[Meow][meowWebView] add Ads Blocker Exceptions success. Operated by meowWebView ~')
                webview.AdsBlockManager.addAdsBlockDisallowedList(this.adsBlocker_exceptions);
              } catch (e) {
                console.error('[ERROR][Meow][meowWebView] add Ads Blocker Exceptions error: ' + e);
              }

              // Set intelligent tracking prevention
              this.bunch_of_tabs.Tabs[Label.index_key].controller.enableIntelligentTrackingPrevention(this.intelligent_tracking_prevention);
              console.log('[Meow][meowWebView] ArkWeb Intelligent Tracking Prevention ' +
              this.intelligent_tracking_prevention.toString() + '!')

              // Restore Web State
              setTimeout(() => {
                if (this.bunch_of_tabs.Tabs[Label.index_key].restore_on_creation) {
                  if (Label.index_key < this.restore_web_state_arrays.length) {
                    this.bunch_of_tabs.restore_web_state(this.restore_web_state_arrays[Label.index_key],
                      Label.index_key);
                  } else {
                    console.error('[ERROR][Meow][meowWebView] Restore web state failed ' +
                      'for an out-of-bound index in restore_web_state_arrays.')
                  }
                }
              }, 0)

              // Set allowed resources
              try {
                let allowed = [
                  this.getUIContext().getHostContext()!.resourceDir,
                // this.getUIContext().getHostContext()!.filesDir,
                // '/data/storage/el2/base/haps/cache'
                ]
                this.bunch_of_tabs.Tabs[Label.index_key].controller.setPathAllowingUniversalAccess(allowed);
                console.log('[meowWebView] Init set allowed resources: [' + allowed.join(", ") + ']');
              } catch (e) {
                console.error('[meowWebView] Init set allowed resources error: ' + e);
              }
            })
            .forceDarkAccess(this.web_force_dark_mode)// Force dark mode
            .onLoadIntercept((event) => {
              if (event) {
                let url: string = event.data.getRequestUrl();
                // Do not intercept data:
                // 检查是否是华为应用市场网页版链接
                if (url.includes('appgallery.huawei.com') || url.includes('haokan.baidu.com/download')) {
                  let want: Want = {
                    action: 'ohos.want.action.appdetail',
                    uri: 'store://appgallery.huawei.com/app/',
                  };
                  meowContext().startAbility(want).then(() => {
                    console.info("Succeeded in starting Ability successfully.")
                  }).catch((error: BusinessError) => {
                    console.error(`Failed to startAbility.Code: ${error.code}, message is ${error.message}`);
                  });
                  return true;
                }
                if (url.substring(0, 5) == 'data:') {
                  return false;
                }
                // Links or urls
                let match_domain_result = match_domain(url);
                if (viewable_domains().includes(match_domain_result[0])) {
                  // Viewable
                  return false;
                } else {
                  // Not viewable, perhaps is a link that can jump?
                  // this.potential_jump_link = url;
                  // this.woofLinkJumper_control.open();
                  return true;
                }
              }
              return false;
            })
            .onPermissionRequest((event) => {
              if (!event) {
                return;
              }
              this.onPermit = () => {
                event.request.grant(event.request.getAccessibleResource());
              }
              this.onDeny = () => {
                event.request.deny();
              }
              this.ask_resources = event.request.getAccessibleResource();
              this.source = event.request.getOrigin();
              console.log('[Meow][meowWebView] Requesting Protected Resources: ' + event.request.getAccessibleResource());

              if (this.ask_resources.length == 1 && this.ask_resources[0] == 'TYPE_SENSOR') {
                // TODO: work out a workable permission manager!
                this.onPermit();
                console.log('[Meow][meowWebView] Permitted TYPE_SENSOR automatically!');
                return;
              }

              this.woofWantProtectedResources_control.open();
            })
            .onClientAuthenticationRequest((event) => {
              console.log('[meowWebView] onClientAuthenticationRequest event.host: ' + event.host);
              console.log('[meowWebView] onClientAuthenticationRequest event.port ' + event.port);
              console.log('[meowWebView] onClientAuthenticationRequest event.keyTypes: ' + event.keyTypes.join('\n'));
              console.log('[meowWebView] onClientAuthenticationRequest event.issuers: ' + event.issuers.join('\n'));
            })
            .onOverScroll(() => {
              console.log('[meowWebView] Over scrolled!')
            })
            .nestedScroll({ scrollForward: NestedScrollMode.SELF_FIRST, scrollBackward: NestedScrollMode.SELF_FIRST })

        } // Webs
        .borderColor(this.color_current_secondary)
        .borderWidth(this.border_width_tab(this.current_sub_tab_index == Label.index_key))
        .width(this.current_sub_tab_index < 0 ? "100%" : this.width_tab())
        .height(this.current_sub_tab_index < 0 ? "100%" : this.height_tab())
        .alignRules(this.current_main_tab_index == Label.index_key ? this.align_rules_main_tab() : this.align_rules_sub_tab())
        .visibility(this.my_visibility(Label.index_key))
        .animation(this.tab_animation)
      }, (Label: tab_label) => Label.timestamp.toString())
    }
    .width("100%")
    .height("100%")

  }

  // Operations

  save_pdf() {
  }

  print() {
    print_web(this.bunch_of_tabs.workingMainTab().controller);
  }

  update_current_info() {
    this.current_title = this.tab_titles[this.current_main_tab_index];
    this.current_url = this.tab_urls[this.current_main_tab_index];
    this.current_url = url_resource_to_meow(this.current_url);
    // translate "resource://" into "meow://"
    this.current_loading_progress = this.tab_loading_progresses[this.current_main_tab_index];
    this.current_is_loading = this.tab_is_loading[this.current_main_tab_index];
    // Set loading progress
    this.current_in_page_searching_keyword = this.bunch_of_tabs.workingMainTab().searching_keyword;
    this.current_in_page_searching_stats_current = this.bunch_of_tabs.workingMainTab().searching_keyword_stats_current;
    this.current_in_page_searching_stats_total = this.bunch_of_tabs.workingMainTab().searching_keyword_stats_total;
  }

  sync_list_info() {
    this.tab_titles = this.bunch_of_tabs.get_all_titles()
    this.tab_urls = this.bunch_of_tabs.get_all_urls()
    this.tab_is_loading = this.bunch_of_tabs.get_all_is_loading();
    this.tab_loading_progresses = this.bunch_of_tabs.get_all_loading_progress()
  }

  update_search_box_text(text: string) {
    if (!this.is_search_input_typing) {
      this.search_input_update_source = 'web';
      this.search_input = url_resource_to_meow(text);
      // Update Input Search Box
    }
    // Update Input Search Box when new page loaded
  }

  on_tab_info_change() {
    if (this.last_timeout_id) {
      clearTimeout(this.last_timeout_id);
    }
    this.last_timeout_id = setTimeout(() => {
      this.tab_animation = animation_default();
    }, 50)
  }

  // 广告过滤功能
  on_use_adblock_state_change() {
    console.log('[Meow][meowWebView] enableAdsBlock: ' + (this.use_adblock ? 'true' : 'false'))
    for (let index = 0; index < this.bunch_of_tabs.Tabs.length; index++) {
      this.bunch_of_tabs.Tabs[index].controller.enableAdsBlock(this.use_adblock);
    }
  }

  refresh_homepage_shortcuts() {
    if (this.homepage_shortcuts_dir == '') {
      return;
    }
    // let result = this.bunch_of_bookmarks.get_folder(this.homepage_shortcuts_dir)?.get_only_bookmarks_content();
    let result = this.bunch_of_bookmarks.get_folder(this.homepage_shortcuts_dir)?.get_content();
    if (result) {
      console.log('[Meow][meowWebView] Directory selected / refreshed for shortcuts: [' + this.homepage_shortcuts_dir + ']');
      this.homepage_shortcuts = result;
      this.bunch_of_settings.set('homepage_shortcuts_bookmarks_dir', this.homepage_shortcuts_dir);
    } else {
      // directory doesn't exist
      console.log('[Meow][meowWebView] Directory selected for shortcuts doesn\'t exist! [' + this.homepage_shortcuts_dir + ']');
      this.homepage_shortcuts = [];
      if (this.homepage_shortcuts_dir != '/') {
        this.homepage_shortcuts_dir = '';
      }
    }
  }

  download_event(event: OnDownloadStartEvent) {
    if (event.url.substring(0, 5) == 'blob:') {
      // Would be already handled by blob delegate!
      return;
    }
    if (event) {
      this.download_non_blob(event.url, event.userAgent, event.contentDisposition, event.contentLength, event.mimetype)
    }
  }

  download_non_blob(url: string, userAgent: string, contentDisposition: string, contentLength: number, mimetype: string) {
    // Save file download additional info
    let try_additional_info = [
      'url: ' + url,
      'userAgent: ' + userAgent,
      'contentDisposition: ' + contentDisposition,
      'contentLength: ' + contentLength.toString(),
      'mimetype: ' + mimetype
    ].join('\n');
    console.log(try_additional_info);

    // Cut out original file name
    let url_split = url.split("/");
    let name_original = url_split[url_split.length-1].split("?")[0];
    name_original = decodeURIComponent(name_original);

    // Cut out overwrite file name
    let name_overwrite = this.cut_filename_overwrite(contentDisposition);

    // Overwrite
    if (name_overwrite != '') {
      name_original = name_overwrite;
    }

    // Call popup
    this.woofWantDownload_control = new CustomDialogController({
      builder: woofWantDownload({
        from: this.current_url,
        file_name: name_original,
        url: url,
        try_additional_info: try_additional_info,
      }),
      alignment: DialogAlignment.Center,
      cornerRadius: 16
    })
    this.woofWantDownload_control.open();
  }

  // Kind of constants

  align_rules_main_tab() {
    let align: AlignRuleOption;
    if (this.tablet_mode) {
      align = { left: { anchor: "__container__", align: HorizontalAlign.Start } }
    } else {
      align = { top: { anchor: "__container__", align: VerticalAlign.Top } }
    }
    return align;
  }

  align_rules_sub_tab() {
    let align: AlignRuleOption;
    if (this.tablet_mode) {
      align = { right: { anchor: "__container__", align: HorizontalAlign.End } }
    } else {
      align = { bottom: { anchor: "__container__", align: VerticalAlign.Bottom } }
    }
    return align;
  }

  width_tab() {
    if (this.tablet_mode) {
      return "50%";
    } else {
      return "100%";
    }
  }

  height_tab() {
    if (this.tablet_mode) {
      return "100%";
    } else {
      return "50%";
    }
  }

  border_width_tab(is_sub: boolean) {
    let border_width: EdgeWidths;
    if (this.tablet_mode) {
      border_width = { left: is_sub ? 2 : 0, top: 0 };
    } else {
      border_width = { top: is_sub ? 2 : 0, left: 0 };
    }
    return border_width;
  }

  my_visibility(index: number) {
    if (!(this.current_main_tab_index == index || this.current_sub_tab_index == index)) {
      // Not present
      return Visibility.None;
    }
    return Visibility.Visible;
  }

  my_js(index: number) {
    if (!this.disable_js) {
      return true;
    }
    // Disable js toggle ON
    if (this.disable_js_all_sites) {
      // Disable on all sites
      return false;
    }
    // Disable on some sites
    if (this.tab_urls[index] && this.disable_js_these_sites.includes(match_domain(this.tab_urls[index])[1])) {
      return false;
    }
    return true;
  }

  my_image(index: number) {
    if (!this.disable_image) {
      return true;
    }
    // Disable image toggle ON
    if (this.disable_image_all_sites) {
      // Disable on all sites
      return false;
    }
    // Disable on some sites
    if (this.tab_urls[index] && this.disable_image_these_sites.includes(match_domain(this.tab_urls[index])[1])) {
      return false;
    }
    return true;
  }

  shortcut_alignItems() {
    let status = this.preferred_hand_left_or_right == 'right';
    if (this.preferred_hand_reverse_homepage_shortcuts) {
      status = !status;
    }
    return status ? HorizontalAlign.End : HorizontalAlign.Start;
  }

  // Ladders
  //书签页相关
  private src_of_tab_index(index: number): string {
    let target_packed_tab_info = this.bunch_of_tabs.Tabs[index];
    if (target_packed_tab_info == undefined) {
      return "";
    } else {
      if (target_packed_tab_info.restore_on_creation) {
        return "";
      } else {
        console.log("srcIndex: " + index)
        console.log('[meowWebView] load: ' + url_meow_to_resource(target_packed_tab_info.url));
        return url_meow_to_resource(target_packed_tab_info.url);
      }
    }
  }

  private determine_extra_background() {
    let need_extra_background = true;
    // Determine background
    if (!this.init_OK) {
      need_extra_background = false;
    }
    if (this.current_sub_tab_index > -1) {
      // Paralleowing
      if (this.current_url == 'meow://home' && this.tab_urls[this.current_sub_tab_index] == 'meow://home') {
        need_extra_background = false;
      }
    } else {
      // Not Paralleowing
      if (this.current_url == 'meow://home') {
        need_extra_background = false;
      }
    }
    this.extra_background = need_extra_background;
  }

  /**
   * Determines if an overwrite file name could be cut out and used
   * @param contentDisposition e.g. "filename='qwq.txt'; type: TEXT"
   * @returns a file name
   * */
  private cut_filename_overwrite(contentDisposition: string) {
    let name_overwrite = '';

    let filename_start = contentDisposition.toLowerCase().indexOf('filename=');
    if (filename_start == -1) {
      return '';
    }
    filename_start += 9;

    let filename_end = contentDisposition.indexOf(';', filename_start);
    if (filename_end == -1) {
      filename_end = contentDisposition.length;
    }

    // cut out file_name_overwrite
    name_overwrite = contentDisposition.slice(filename_start, filename_end);

    // eliminate quotes
    let last_idx = name_overwrite.length - 1;
    if (["'", '"'].includes(name_overwrite[last_idx])) {
      name_overwrite = name_overwrite.slice(1, last_idx);
    }

    return name_overwrite;
  }
}

export default meowWebView;

@Component
struct shortcutButton {
  @Prop my_index: number;
  @Prop bookmark: unified_item;
  // Environment
  @StorageLink('current_url') current_url: string = "=￣ω￣=";
  @StorageLink('bunch_of_bookmarks') bunch_of_bookmarks: bunch_of_bookmarks = new bunch_of_bookmarks('Bookmarks~Meow');
  // Settings - Accessibility
  @StorageLink('preferred_hand_left_or_right') preferred_hand_left_or_right: string = 'right';
  @StorageLink('preferred_hand_reverse_homepage_shortcuts') preferred_hand_reverse_homepage_shortcuts: boolean = false;
  // Gateways
  @StorageLink('universal_new_tab_gateway') new_tab_gateway: string = "";
  // Colors
  @StorageProp('color_current_primary') color_current_primary: ResourceColor = $r('app.color.start_window_background');
  @StorageProp('color_current_secondary') color_current_secondary: ResourceColor = $r('app.color.block_color');
  @StorageProp('color_current_font') color_current_font: ResourceColor = $r('app.color.font_color_title');
  // SHow
  @State show_contents: Visibility = Visibility.None;
  @State show: Visibility = Visibility.Hidden;
  @State offset_y: number = 50;

  build() {
    Column({ space: 10 }) {
      Button((this.bookmark.get_item().get_type() == 'folder' ? (this.show_contents == Visibility.Visible ? '󰃆  ' : '󰃅  ') : '')
        + this.bookmark.get_item().get_label())// Shortcut "󰄏"
        .type(ButtonType.Capsule)
        .backgroundColor(this.color_current_secondary)
        .fontColor(this.color_current_font)
        .border({
          width: 2,
          color: "transparent"
        })
        .fontSize(fontSize_Large())
        .fontWeight(FontWeight.Regular)
        .height(capsule_bar_height())
        .visibility(this.show)
        .offset({ y: this.offset_y })
        .clickEffect(click_effect_default())
        .animation(animation_default())
        .onAppear(() => {
          setTimeout(() => {
            this.show = Visibility.Visible;
            this.offset_y = 0;
            // Animation of floating up
          }, this.get_animation_timeout())
        })
        .onClick(() => {
          let item = this.bookmark.get_item();
          if (item.get_type() == 'bookmark') {
            // Is bookmark, access website
            setTimeout(() => {
              this.new_tab_gateway = (item as bookmark).get_link();
              this.current_url = (item as bookmark).get_link();
            }, 100)
          } else {
            // Is folder, expand contents
            if (this.show_contents == Visibility.None) {
              this.show_contents = Visibility.Visible;
            } else {
              this.show_contents = Visibility.None;
            }
          }
        })

      if (this.bookmark.get_item().get_type() == 'folder') {
        Column({ space: 10 }) {
          ForEach((this.bookmark.get_item() as folder).get_content(), (shortcut: unified_item, key: number) => {
            shortcutButton({
              bookmark: shortcut,
              my_index: key,
            })
          })
        }
        .alignItems(this.get_alignItems())
        .visibility(this.show_contents)
        .animation(animation_default())
      }
    }
    .alignItems(this.get_alignItems())
    .padding(this.show_contents == Visibility.Visible ? (this.is_right_align() ? { right: 30 } : { left: 30 }) : {})
    .animation(animation_default())
  }

  is_right_align() {
    return this.preferred_hand_left_or_right == 'right' && !this.preferred_hand_reverse_homepage_shortcuts
  }

  get_alignItems() {
    if (this.is_right_align()) {
      return HorizontalAlign.End;
    } else {
      return HorizontalAlign.Start
    }
  }

  get_animation_timeout() {
    let unit_interval = 40;
    if (this.my_index < 5) {
      unit_interval = 80;
    } else if (this.my_index < 10) {
      unit_interval = 70;
    } else {
      unit_interval = 60;
    }
    return this.my_index * unit_interval + 100;
  }
}