import "./stream-editor.css";
import { useEffect, useState, useCallback } from "react";
import { NostrEvent } from "@snort/system";
import { unixNow } from "@snort/shared";
import { TagsInput } from "react-tag-input-component";
import { FormattedMessage, useIntl } from "react-intl";

import AsyncButton from "./async-button";
import { StreamState } from "../index";
import { findTag } from "../utils";
import { useLogin } from "hooks/login";
import { NewGoalDialog } from "element/new-goal";
import { useGoals } from "hooks/goals";

export interface StreamEditorProps {
  ev?: NostrEvent;
  onFinish?: (ev: NostrEvent) => void;
  options?: {
    canSetTitle?: boolean;
    canSetSummary?: boolean;
    canSetImage?: boolean;
    canSetStatus?: boolean;
    canSetStream?: boolean;
    canSetTags?: boolean;
    canSetContentWarning?: boolean;
  };
}

interface GoalSelectorProps {
  goal?: string;
  pubkey: string;
  onGoalSelect: (g: string) => void;
}

function GoalSelector({ goal, pubkey, onGoalSelect }: GoalSelectorProps) {
  const goals = useGoals(pubkey, true);
  const { formatMessage } = useIntl();
  return (
    <select defaultValue={goal} onChange={ev => onGoalSelect(ev.target.value)}>
      <option value="">{formatMessage({ defaultMessage: "Select a goal..." })}</option>
      {goals?.map(goal => (
        <option key={goal.id} value={goal.id}>
          {goal.content}
        </option>
      ))}
    </select>
  );
}

export function StreamEditor({ ev, onFinish, options }: StreamEditorProps) {
  const [title, setTitle] = useState("");
  const [summary, setSummary] = useState("");
  const [image, setImage] = useState("");
  const [stream, setStream] = useState("");
  const [status, setStatus] = useState("");
  const [start, setStart] = useState<string>();
  const [tags, setTags] = useState<string[]>([]);
  const [contentWarning, setContentWarning] = useState(false);
  const [isValid, setIsValid] = useState(false);
  const [goal, setGoal] = useState<string | undefined>();
  const login = useLogin();
  const { formatMessage } = useIntl();

  useEffect(() => {
    setTitle(findTag(ev, "title") ?? "");
    setSummary(findTag(ev, "summary") ?? "");
    setImage(findTag(ev, "image") ?? "");
    setStream(findTag(ev, "streaming") ?? "");
    setStatus(findTag(ev, "status") ?? StreamState.Live);
    setStart(findTag(ev, "starts"));
    setTags(ev?.tags.filter(a => a[0] === "t").map(a => a[1]) ?? []);
    setContentWarning(findTag(ev, "content-warning") !== undefined);
    setGoal(findTag(ev, "goal"));
  }, [ev?.id]);

  const validate = useCallback(() => {
    if (title.length < 2) {
      return false;
    }
    if (stream.length < 5 || !stream.match(/^https?:\/\/.*\.m3u8?$/i)) {
      return false;
    }
    if (image.length > 0 && !image.match(/^https?:\/\//i)) {
      return false;
    }
    return true;
  }, [title, image, stream]);

  useEffect(() => {
    setIsValid(ev !== undefined || validate());
  }, [validate, title, summary, image, stream]);

  async function publishStream() {
    const pub = login?.publisher();
    if (pub) {
      const evNew = await pub.generic(eb => {
        const now = unixNow();
        const dTag = findTag(ev, "d") ?? now.toString();
        const starts = start ?? now.toString();
        const ends = findTag(ev, "ends") ?? now.toString();
        eb.kind(30311)
          .tag(["d", dTag])
          .tag(["title", title])
          .tag(["summary", summary])
          .tag(["image", image])
          .tag(["streaming", stream])
          .tag(["status", status])
          .tag(["starts", starts]);
        if (status === StreamState.Ended) {
          eb.tag(["ends", ends]);
        }
        for (const tx of tags) {
          eb.tag(["t", tx.trim()]);
        }
        if (contentWarning) {
          eb.tag(["content-warning", "nsfw"]);
        }
        if (goal && goal.length > 0) {
          eb.tag(["goal", goal]);
        }
        return eb;
      });
      console.debug(evNew);
      onFinish && onFinish(evNew);
    }
  }

  function toDateTimeString(n: number) {
    return new Date(n * 1000).toISOString().substring(0, -1);
  }

  function fromDateTimeString(s: string) {
    return Math.floor(new Date(s).getTime() / 1000);
  }

  return (
    <>
      <h3>{ev ? "Edit Stream" : "New Stream"}</h3>
      {(options?.canSetTitle ?? true) && (
        <div>
          <p>
            <FormattedMessage defaultMessage="Title" />
          </p>
          <div className="paper">
            <input
              type="text"
              placeholder={formatMessage({ defaultMessage: "What are we steaming today?" })}
              value={title}
              onChange={e => setTitle(e.target.value)}
            />
          </div>
        </div>
      )}
      {(options?.canSetSummary ?? true) && (
        <div>
          <p>
            <FormattedMessage defaultMessage="Summary" />
          </p>
          <div className="paper">
            <input
              type="text"
              placeholder={formatMessage({ defaultMessage: "A short description of the content" })}
              value={summary}
              onChange={e => setSummary(e.target.value)}
            />
          </div>
        </div>
      )}
      {(options?.canSetImage ?? true) && (
        <div>
          <p>
            <FormattedMessage defaultMessage="Cover Image" />
          </p>
          <div className="paper">
            <input type="text" placeholder="https://" value={image} onChange={e => setImage(e.target.value)} />
          </div>
        </div>
      )}
      {(options?.canSetStream ?? true) && (
        <div>
          <p>
            <FormattedMessage defaultMessage="Stream URL" />
          </p>
          <div className="paper">
            <input type="text" placeholder="https://" value={stream} onChange={e => setStream(e.target.value)} />
          </div>
          <small>
            <FormattedMessage defaultMessage="Stream type should be HLS" />
          </small>
        </div>
      )}
      {(options?.canSetStatus ?? true) && (
        <>
          <div>
            <p>
              <FormattedMessage defaultMessage="Status" />
            </p>
            <div className="flex g12">
              {[StreamState.Live, StreamState.Planned, StreamState.Ended].map(v => (
                <span className={`pill${status === v ? " active" : ""}`} onClick={() => setStatus(v)} key={v}>
                  {v}
                </span>
              ))}
            </div>
          </div>
          {status === StreamState.Planned && (
            <div>
              <p>
                <FormattedMessage defaultMessage="Start Time" />
              </p>
              <div className="paper">
                <input
                  type="datetime-local"
                  value={toDateTimeString(Number(start ?? "0"))}
                  onChange={e => setStart(fromDateTimeString(e.target.value).toString())}
                />
              </div>
            </div>
          )}
        </>
      )}
      {(options?.canSetTags ?? true) && (
        <div>
          <p>
            <FormattedMessage defaultMessage="Tags" />
          </p>
          <div className="paper">
            <TagsInput value={tags} onChange={setTags} placeHolder="Music,DJ,English" separators={["Enter", ","]} />
          </div>
        </div>
      )}
      {login?.pubkey && (
        <>
          <div>
            <p>
              <FormattedMessage defaultMessage="Goal" />
            </p>
            <div className="paper">
              <GoalSelector goal={goal} pubkey={login?.pubkey} onGoalSelect={setGoal} />
            </div>
          </div>
          <NewGoalDialog />
        </>
      )}
      {(options?.canSetContentWarning ?? true) && (
        <div className="flex g12 content-warning">
          <div>
            <input type="checkbox" checked={contentWarning} onChange={e => setContentWarning(e.target.checked)} />
          </div>
          <div>
            <div className="warning">
              <FormattedMessage defaultMessage="NSFW Content" />
            </div>
            <FormattedMessage defaultMessage="Check here if this stream contains nudity or pornographic content." />
          </div>
        </div>
      )}
      <div>
        <AsyncButton type="button" className="btn btn-primary wide" disabled={!isValid} onClick={publishStream}>
          {ev ? <FormattedMessage defaultMessage="Save" /> : <FormattedMessage defaultMessage="Start Stream" />}
        </AsyncButton>
      </div>
    </>
  );
}
