import { h, Component } from "preact";
import { IVault, ViewNote } from "../../../notes";
import { Trash2 as Trash, X, Save } from "preact-feather";

import Navigation from "../../../navigation";
import { YesNoModal } from "../../modals/YesNoModal";
import Notifications, { MessageType } from "../../../notifications";

const minRows = 3;
export default class EntryComponent extends Component<
   { vault: Promise<IVault>; id: string | undefined; note: string | undefined },
   { title: string; changed: boolean }
> {
   private text: string = "";
   private vault: IVault;
   // private lineHeight: number = 24;
   private note: ViewNote;

   private rows: number = minRows;

   private skip_save: boolean = false;

   private inputElm: HTMLInputElement;

   constructor(props) {
      super(props);
      this.state = { changed: false, title: "" };
      this.textAreaChange = this.textAreaChange.bind(this);
      this.textAreaKeyPress = this.textAreaKeyPress.bind(this);
   }

   private toVault() {
      history.back();
   }

   componentDidMount() {
      this.inputElm.focus();
   }

   async componentWillMount() {
      this.text = "";
      this.vault = undefined;
      this.note = undefined;
      this.rows = minRows;
      this.skip_save = false;
      this.setState({ changed: false, title: "" });
      try {
         this.skip_save = false;

         this.vault = await this.props.vault;
         let note: ViewNote;
         let changed = false;
         if (this.props.id) note = await this.vault.getNote(this.props.id);
         else {
            note = this.vault.newNote();
            if (this.props.note) {
               note.__value = this.props.note;
               changed = true;
            }
         }

         if (!note) {
            Notifications.sendNotification(
               "Note not found!",
               MessageType.ERROR
            );
         } else {
            this.note = note;
            this.text = note.__value;
            let rows = this.getRows(this.text);
            if (rows !== this.rows) {
               this.rows = rows;
            }
            let [title] = this.text.split("\n", 1);
            this.setState({ title, changed });
         }
      } catch (err) {
         Notifications.sendError(err);
      }
   }

   private async save() {
      try {
         if (this.state.changed) {
            this.note.__value = this.text;
            await this.vault.saveNote(this.note);
            this.setState({ changed: false });
         }
      } catch (err) {
         Notifications.sendError(err);
      }
   }

   componentWillUnmount() {
      if (!this.skip_save) this.save();
   }

   strToNr(value: string) {
      let match = value.match(/\d/g);
      return Number(match.join(""));
   }

   getRows(value: string) {
      const lines = (value.match(/\r?\n/g) || "").length + 1;
      return Math.max(lines + 1, minRows);
   }

   textAreaChange(evt: KeyboardEvent) {
      if (evt.keyCode === 17 || evt.keyCode === 27) return; //No character, so not relevant for this function
      if (!this.state.changed && this.textAreaKeyPress(evt))
         this.setState({ changed: true });

      let target = evt.target as HTMLTextAreaElement;
      let value = target.value;

      this.text = value;

      let [title] = value.split("\n", 1);
      if (title !== this.state.title) this.setState({ title });

      let rows = this.getRows(value);
      if (rows !== this.rows) {
         target.rows = rows;
         this.rows = rows;
      }
   }

   async exitHandler() {
      if (this.state.changed) {
         let modal = new YesNoModal("Really want to quit?");
         let res = await modal.getResult();
         if (res === true) {
            this.skip_save = true;
            this.toVault();
         }
      } else this.toVault();
   }

   textAreaKeyPress(evt: KeyboardEvent) {
      console.log(evt);
      if ((evt.keyCode === 83 || evt.keyCode === 13) && evt.ctrlKey) {
         evt.preventDefault();
         this.save();
         return false;
      } else if (evt.keyCode === 27) {
         evt.preventDefault();
         this.exitHandler();
         return false;
      }
      return true;
   }

   render() {
      const save_handler = async () => {
         await this.save();
         Navigation.setPage(
            "/vault",
            { id: this.vault.id },
            { entry: "false" },
            true
         );
         this.toVault();
      };

      const delete_handler = async () => {
         await this.vault.deleteNote(this.props.id);
         this.toVault();
      };

      console.log("Rerender");

      return (
         <div>
            <header class="header">
               <a class="header-icon-button" onClick={() => this.exitHandler()}>
                  <X height={undefined} width={undefined} />
               </a>
               {this.state.changed ? (
                  <a
                     class="header-icon-button"
                     style="margin-left: 0.5em;"
                     onClick={() => save_handler()}
                  >
                     <Save height={undefined} width={undefined} />
                  </a>
               ) : undefined}
               <h3 style="display:inline" class="button header-title">
                  {this.state.title}
               </h3>
               <a class="header-icon-button" onClick={() => delete_handler()}>
                  <Trash height={undefined} width={undefined} />
               </a>
            </header>
            <div class="container">
               <textarea
                  value={this.text}
                  rows={this.rows}
                  class="inp"
                  style="width:100%;"
                  onInput={this.textAreaChange}
                  onKeyDown={this.textAreaKeyPress}
                  onChange={this.textAreaChange}
                  ref={(elm) => (this.inputElm = elm)}
               />
            </div>
         </div>
      );
   }
}
