import { client } from "./client.mjs";
import { html, create, styled } from "./misc.mjs";

const sample_texts = [
  {
    text: "天气预报显示,今天会有小雨,请大家出门时记得带伞。降温的天气也提醒我们要适时添衣保暖。",
  },
  {
    text: "公司的年度总结会议将在下周三举行,请各部门提前准备好相关材料,确保会议顺利进行。",
  },
  {
    text: "今天的午餐菜单包括烤鸡、沙拉和蔬菜汤,大家可以根据自己的口味选择适合的菜品。",
  },
  {
    text: "请注意,电梯将在下午两点进行例行维护,预计需要一个小时的时间,请大家在此期间使用楼梯。",
  },
  {
    text: "图书馆新到了一批书籍,涵盖了文学、科学和历史等多个领域,欢迎大家前来借阅。",
  },
];

let history_index = 0;

const useStore = create((set, get) => ({
  tts: {
    text: "你好,这里是一段ChatTTS Forge项目的示例文本。",
    spk: "female2",
    style: "chat",
    temperature: 0.3,
    top_P: 1,
    top_K: 20,
    seed: -1,
    format: "mp3",
    prompt1: "",
    prompt2: "",
    prefix: "",
  },
  styles: [],
  speakers: [],

  ui: {
    loading: false,
    // 历史生成结果 { audio: Blob, url: string, params: object }
    history: [],
  },

  async synthesizeTTS() {
    const params = structuredClone(get().tts);
    const blob = await client.synthesizeTTS({
      ...params,
    });
    const blob_url = URL.createObjectURL(blob);
    set({
      ui: {
        ...get().ui,
        history: [
          ...get().ui.history,
          {
            id: history_index++,
            audio: blob,
            url: blob_url,
            params: params,
          },
        ],
      },
    });
  },
  setStyles(styles) {
    set({ styles });
  },
  setSpeakers(speakers) {
    set({ speakers });
  },
  setTTS(tts) {
    set({
      tts: {
        ...get().tts,
        ...tts,
      },
    });
  },
  setUI(ui) {
    set({
      ui: {
        ...get().ui,
        ...ui,
      },
    });
  },
}));

window.addEventListener("load", async () => {
  const styles = await client.listStyles();
  const speakers = await client.listSpeakers();
  console.log("styles:", styles);
  console.log("speakers:", speakers);
  useStore.get().setStyles(styles.data);
  useStore.get().setSpeakers(speakers.data);
});

const TTSPageContainer = styled.div`
  h1 {
    margin-bottom: 1rem;
  }

  p {
    margin-bottom: 1rem;
  }

  #app {
    margin-top: 1rem;
  }

  textarea {
    width: 100%;
    height: 10rem;
    margin-bottom: 1rem;

    min-height: 10rem;

    resize: vertical;
  }

  button {
    padding: 0.5rem 1rem;
    background-color: #007bff;
    color: white;
    border: none;
    cursor: pointer;
  }

  button:hover {
    background-color: #0056b3;
  }

  button:disabled {
    background-color: #6c757d;
    cursor: not-allowed;
  }

  fieldset {
    margin-top: 1rem;
    padding: 1rem;
    border: 1px solid #333;
  }

  legend {
    font-weight: bold;
  }

  label {
    display: block;
    margin-bottom: 0.5rem;
  }

  select,
  input[type="range"],
  input[type="number"] {
    width: 100%;
    margin-top: 0.25rem;
  }

  input[type="range"] {
    width: calc(100% - 2rem);
  }

  input[type="number"] {
    width: calc(100% - 2rem);
    padding: 0.5rem;
  }

  input[type="text"] {
    width: 100%;
    padding: 0.5rem;
  }

  audio {
    margin-top: 1rem;
  }

  textarea,
  input,
  select {
    background-color: #333;
    color: white;
    border: 1px solid #333;
    border-radius: 0.25rem;
    padding: 0.5rem;
  }

  table {
    width: 100%;
    border-collapse: collapse;
  }

  th,
  td {
    padding: 0.5rem;
    border: 1px solid #333;
  }

  th {
    background-color: #333;
    color: white;
  }

  th:nth-child(2),
  td:nth-child(2) {
    width: 60%;
  }

  .content-body {
    display: flex;
    gap: 1rem;
  }

  .content-left {
    flex: 1;
  }

  .content-right {
    flex: 4;
  }

  h1 small {
    font-weight: 100;
    font-size: 0.5em;
    font-weight: normal;
  }

  .btn-synthesize {
    background-color: #007bff;
    color: white;
    border: none;
    cursor: pointer;
    padding: 0.5rem 1rem;
  }

  .btn-synthesize:hover {
    background-color: #0056b3;
  }

  .btn-synthesize:disabled {
    background-color: #6c757d;
    cursor: not-allowed;
  }

  .btn-clear {
    background-color: #dc3545;
    color: white;
    border: none;
    cursor: pointer;
    padding: 0.5rem 1rem;
  }

  .btn-clear:hover {
    background-color: #bd2130;
  }

  .btn-clear:disabled {
    background-color: #6c757d;
    cursor: not-allowed;
  }

  .btn-random {
    background-color: #28a745;
    color: white;
    border: none;
    cursor: pointer;
    padding: 0.5rem 1rem;
  }

  .btn-random:hover {
    background-color: #218838;
  }

  pre {
    white-space: pre-wrap;
  }

  .sample-texts {
    width: unset;
    display: inline-block;
    padding: 0.5rem;
    margin-bottom: 1rem;
  }
`;

export const TTSPage = () => {
  const { tts, setTTS, synthesizeTTS, ui, setUI, speakers, styles } =
    useStore();

  const request = async () => {
    if (ui.loading) {
      return;
    }
    setUI({ loading: true });
    try {
      await synthesizeTTS();
    } catch (error) {
      console.error("Error synthesizing TTS:", error);
    } finally {
      setUI({ loading: false });
    }
  };

  return html`
    <${TTSPageContainer}>
      <textarea
        value=${tts.text}
        onInput=${(e) => setTTS({ text: e.target.value })}
      ></textarea>
      <button class="btn-synthesize" disabled=${ui.loading} onClick=${request}>
        ${ui.loading ? "Synthesizing..." : "Synthesize"}
      </button>
      <button
        class="btn-clear"
        disabled=${ui.loading}
        onClick=${() => setUI({ history: [] })}
      >
        Clear History
      </button>

      <select
        placeholder="Sample Text"
        class="sample-texts"
        value=${tts.text}
        onChange=${(e) => setTTS({ text: e.target.value })}
      >
        ${sample_texts.map(
          (item, index) => html`
            <option key=${index} value=${item.text}>
              Sample ${index + 1}: ${item.text.slice(0, 10) + "..."}
            </option>
          `
        )}
      </select>

      <div class="content-body">
        <fieldset class="content-left">
          <legend>Options</legend>
          <label>
            Speaker:
            <select
              value=${tts.spk}
              onChange=${(e) => setTTS({ spk: e.target.value })}
            >
              <option value="-1">*random</option>
              ${speakers.map(
                (spk) => html`
                  <option key=${spk.index} value=${spk.name}>
                    ${spk.name}
                  </option>
                `
              )}
            </select>
          </label>
          <label>
            Style:
            <select
              value=${tts.style}
              onChange=${(e) => setTTS({ style: e.target.value })}
            >
              <option value="">*auto</option>
              ${styles.map(
                (style) => html`
                  <option key=${style.id} value=${style.name}>
                    ${style.name}
                  </option>
                `
              )}
            </select>
          </label>
          <label>
            Temperature:
            <input
              type="range"
              min="0.01"
              max="2"
              step="0.01"
              value=${tts.temperature}
              onInput=${(e) => setTTS({ temperature: e.target.value })}
            />
            ${tts.temperature}
          </label>
          <label>
            Top P:
            <input
              type="range"
              min="0.01"
              max="1"
              step="0.01"
              value=${tts.top_P}
              onInput=${(e) => setTTS({ top_P: e.target.value })}
            />
            ${tts.top_P}
          </label>
          <label>
            Top K:
            <input
              type="range"
              min="1"
              max="50"
              step="1"
              value=${tts.top_K}
              onInput=${(e) => setTTS({ top_K: e.target.value })}
            />
            ${tts.top_K}
          </label>
          <label>
            Seed:
            <input
              type="number"
              value=${tts.seed}
              onInput=${(e) => setTTS({ seed: e.target.value })}
            />
            <button
              class="btn-random"
              onClick=${() =>
                setTTS({ seed: Math.floor(Math.random() * 2 ** 32 - 1) })}
            >
              Random
            </button>
          </label>
          <label>
            Format
            <select
              value=${tts.format}
              onChange=${(e) => setTTS({ format: e.target.value })}
            >
              <option value="mp3">MP3</option>
              <option value="wav">WAV</option>
            </select>
          </label>
          <label>
            Prompt1:
            <input
              type="text"
              value=${tts.prompt1}
              onInput=${(e) => setTTS({ prompt1: e.target.value })}
            />
          </label>
          <label>
            Prompt2:
            <input
              type="text"
              value=${tts.prompt2}
              onInput=${(e) => setTTS({ prompt2: e.target.value })}
            />
          </label>
          <label>
            Prefix:
            <input
              type="text"
              value=${tts.prefix}
              onInput=${(e) => setTTS({ prefix: e.target.value })}
            />
          </label>
        </fieldset>

        <fieldset class="content-right">
          <legend>History</legend>
          <table>
            <thead>
              <tr>
                <th>id</th>
                <th>Params</th>
                <th>Audio</th>
              </tr>
            </thead>
            <tbody>
              ${[...ui.history].reverse().map(
                (item, index) => html`
                  <tr key=${item.id}>
                    <td>${item.id}</td>
                    <td>
                      <pre>${JSON.stringify(item.params, null, 2)}</pre>
                    </td>
                    <td>
                      <audio controls>
                        <source
                          src=${item.url}
                          type="audio/${item.params.format}"
                        />
                      </audio>
                    </td>
                  </tr>
                `
              )}
            </tbody>
          </table>
        </fieldset>
      </div>
    <//>
  `;
};