import { EF_INTERACTIVE } from "../EF_INTERACTIVE.js";
import { EFSourceMixin } from "./EFSourceMixin.js";
import { EFTemporal } from "./EFTemporal.js";
import { FetchMixin } from "./FetchMixin.js";
import { EFAudio } from "./EFAudio.js";
import { EFVideo } from "./EFVideo.js";
import { CrossUpdateController } from "./CrossUpdateController.js";
import { Task } from "@lit/task";
import { LitElement, css, html } from "lit";
import { customElement, property } from "lit/decorators.js";
import _decorate from "@oxc-project/runtime/helpers/decorate";
const stopWords = new Set([
	"",
	".",
	"!",
	"?",
	","
]);
let EFCaptionsActiveWord = class EFCaptionsActiveWord$1 extends EFTemporal(LitElement) {
	constructor(..._args) {
		super(..._args);
		this.wordStartMs = 0;
		this.wordEndMs = 0;
		this.wordText = "";
		this.hidden = false;
	}
	static {
		this.styles = [css`
      :host {
        display: inline-block;
        white-space: pre;
      }
      :host([hidden]) {
        display: none;
      }
    `];
	}
	render() {
		if (stopWords.has(this.wordText)) {
			this.hidden = true;
			return void 0;
		}
		this.hidden = false;
		return html` ${this.wordText.trim()} `;
	}
	get startTimeMs() {
		return this.wordStartMs || 0;
	}
	get durationMs() {
		return this.wordEndMs - this.wordStartMs;
	}
};
_decorate([property({
	type: Number,
	attribute: false
})], EFCaptionsActiveWord.prototype, "wordStartMs", void 0);
_decorate([property({
	type: Number,
	attribute: false
})], EFCaptionsActiveWord.prototype, "wordEndMs", void 0);
_decorate([property({
	type: String,
	attribute: false
})], EFCaptionsActiveWord.prototype, "wordText", void 0);
_decorate([property({
	type: Boolean,
	reflect: true
})], EFCaptionsActiveWord.prototype, "hidden", void 0);
EFCaptionsActiveWord = _decorate([customElement("ef-captions-active-word")], EFCaptionsActiveWord);
let EFCaptionsSegment = class EFCaptionsSegment$1 extends EFTemporal(LitElement) {
	constructor(..._args2) {
		super(..._args2);
		this.segmentStartMs = 0;
		this.segmentEndMs = 0;
		this.segmentText = "";
		this.hidden = false;
	}
	static {
		this.styles = [css`
      :host {
        display: block;
      }
      :host([hidden]) {
        display: none;
      }
    `];
	}
	render() {
		if (stopWords.has(this.segmentText)) {
			this.hidden = true;
			return void 0;
		}
		this.hidden = false;
		return html`${this.segmentText}`;
	}
	get startTimeMs() {
		return this.segmentStartMs || 0;
	}
	get durationMs() {
		return this.segmentEndMs - this.segmentStartMs;
	}
};
_decorate([property({
	type: Number,
	attribute: false
})], EFCaptionsSegment.prototype, "segmentStartMs", void 0);
_decorate([property({
	type: Number,
	attribute: false
})], EFCaptionsSegment.prototype, "segmentEndMs", void 0);
_decorate([property({
	type: String,
	attribute: false
})], EFCaptionsSegment.prototype, "segmentText", void 0);
_decorate([property({
	type: Boolean,
	reflect: true
})], EFCaptionsSegment.prototype, "hidden", void 0);
EFCaptionsSegment = _decorate([customElement("ef-captions-segment")], EFCaptionsSegment);
let EFCaptionsBeforeActiveWord = class EFCaptionsBeforeActiveWord$1 extends EFCaptionsSegment {
	constructor(..._args3) {
		super(..._args3);
		this.hidden = false;
		this.segmentText = "";
		this.segmentStartMs = 0;
		this.segmentEndMs = 0;
	}
	static {
		this.styles = [css`
      :host {
        display: inline-block;
        white-space: pre;
      }
      :host([hidden]) {
        display: none;
      }
    `];
	}
	render() {
		if (stopWords.has(this.segmentText)) {
			this.hidden = true;
			return void 0;
		}
		this.hidden = false;
		return html` ${this.segmentText}`;
	}
	get startTimeMs() {
		return this.segmentStartMs || 0;
	}
	get durationMs() {
		return this.segmentEndMs - this.segmentStartMs;
	}
};
_decorate([property({
	type: Boolean,
	reflect: true
})], EFCaptionsBeforeActiveWord.prototype, "hidden", void 0);
_decorate([property({
	type: String,
	attribute: false
})], EFCaptionsBeforeActiveWord.prototype, "segmentText", void 0);
_decorate([property({
	type: Number,
	attribute: false
})], EFCaptionsBeforeActiveWord.prototype, "segmentStartMs", void 0);
_decorate([property({
	type: Number,
	attribute: false
})], EFCaptionsBeforeActiveWord.prototype, "segmentEndMs", void 0);
EFCaptionsBeforeActiveWord = _decorate([customElement("ef-captions-before-active-word")], EFCaptionsBeforeActiveWord);
let EFCaptionsAfterActiveWord = class EFCaptionsAfterActiveWord$1 extends EFCaptionsSegment {
	constructor(..._args4) {
		super(..._args4);
		this.hidden = false;
		this.segmentText = "";
		this.segmentStartMs = 0;
		this.segmentEndMs = 0;
	}
	static {
		this.styles = [css`
      :host {
        display: inline-block;
        white-space: pre;
      }
      :host([hidden]) {
        display: none;
      }
    `];
	}
	render() {
		if (stopWords.has(this.segmentText)) {
			this.hidden = true;
			return void 0;
		}
		this.hidden = false;
		return html`${this.segmentText} `;
	}
	get startTimeMs() {
		return this.segmentStartMs || 0;
	}
	get durationMs() {
		return this.segmentEndMs - this.segmentStartMs;
	}
};
_decorate([property({
	type: Boolean,
	reflect: true
})], EFCaptionsAfterActiveWord.prototype, "hidden", void 0);
_decorate([property({
	type: String,
	attribute: false
})], EFCaptionsAfterActiveWord.prototype, "segmentText", void 0);
_decorate([property({
	type: Number,
	attribute: false
})], EFCaptionsAfterActiveWord.prototype, "segmentStartMs", void 0);
_decorate([property({
	type: Number,
	attribute: false
})], EFCaptionsAfterActiveWord.prototype, "segmentEndMs", void 0);
EFCaptionsAfterActiveWord = _decorate([customElement("ef-captions-after-active-word")], EFCaptionsAfterActiveWord);
let EFCaptions = class EFCaptions$1 extends EFSourceMixin(EFTemporal(FetchMixin(LitElement)), { assetType: "caption_files" }) {
	constructor(..._args5) {
		super(..._args5);
		this.displayMode = "segment";
		this.contextWords = 3;
		this.targetSelector = "";
		this.wordStyle = "";
		this.activeWordContainers = this.getElementsByTagName("ef-captions-active-word");
		this.segmentContainers = this.getElementsByTagName("ef-captions-segment");
		this.beforeActiveWordContainers = this.getElementsByTagName("ef-captions-before-active-word");
		this.afterActiveWordContainers = this.getElementsByTagName("ef-captions-after-active-word");
		this.md5SumLoader = new Task(this, {
			autoRun: false,
			args: () => [this.target, this.fetch],
			task: async ([_target, fetch], { signal }) => {
				const md5Path = `/@ef-asset/${this.targetElement.src ?? ""}`;
				const response = await fetch(md5Path, {
					method: "HEAD",
					signal
				});
				return response.headers.get("etag") ?? void 0;
			}
		});
		this.transcriptionDataTask = new Task(this, {
			autoRun: EF_INTERACTIVE,
			args: () => [this.transcriptionsPath(), this.fetch],
			task: async ([transcriptionsPath, fetch], { signal }) => {
				if (!transcriptionsPath) return null;
				const response = await fetch(transcriptionsPath, { signal });
				return response.json();
			}
		});
		this.fragmentIndexTask = new Task(this, {
			autoRun: EF_INTERACTIVE,
			args: () => [this.transcriptionDataTask.value, this.ownCurrentTimeMs],
			task: async ([transcription, ownCurrentTimeMs]) => {
				if (!transcription) return null;
				const fragmentIndex = Math.floor(ownCurrentTimeMs / transcription.work_slice_ms);
				return fragmentIndex;
			}
		});
		this.transcriptionFragmentDataTask = new Task(this, {
			autoRun: EF_INTERACTIVE,
			args: () => [
				this.transcriptionDataTask.value,
				this.fragmentIndexTask.value,
				this.fetch
			],
			task: async ([transcription, fragmentIndex, fetch], { signal }) => {
				if (transcription === null || transcription === void 0 || fragmentIndex === null || fragmentIndex === void 0) return null;
				const fragmentPath = this.transcriptionFragmentPath(transcription.id, fragmentIndex);
				const response = await fetch(fragmentPath, { signal });
				return response.json();
			}
		});
		this.frameTask = new Task(this, {
			autoRun: EF_INTERACTIVE,
			args: () => [this.transcriptionFragmentDataTask.status],
			task: async () => {
				await this.transcriptionFragmentDataTask.taskComplete;
			}
		});
	}
	static {
		this.styles = [css`
      :host {
        display: flex;
        flex-wrap: wrap;
        align-items: baseline;
        width: fit-content;
      }
      ::slotted(*) {
        margin: 0;
        padding: 0;
      }
    `];
	}
	set target(value) {
		this.targetSelector = value;
	}
	render() {
		return html`<slot></slot>`;
	}
	transcriptionsPath() {
		if (this.targetElement.assetId) return `${this.apiHost}/api/v1/isobmff_files/${this.targetElement.assetId}/transcription`;
		return null;
	}
	captionsPath() {
		if (this.targetElement.assetId) return `${this.apiHost}/api/v1/caption_files/${this.targetElement.assetId}`;
		const targetSrc = this.targetElement.src;
		return `/@ef-captions/${targetSrc}`;
	}
	transcriptionFragmentPath(transcriptionId, fragmentIndex) {
		return `${this.apiHost}/api/v1/transcriptions/${transcriptionId}/fragments/${fragmentIndex}`;
	}
	connectedCallback() {
		super.connectedCallback();
		if (this.targetElement) new CrossUpdateController(this.targetElement, this);
	}
	updated(_changedProperties) {
		this.updateTextContainers();
	}
	updateTextContainers() {
		const transcriptionFragment = this.transcriptionFragmentDataTask.value;
		if (!transcriptionFragment) return;
		const currentTimeMs = this.targetElement.currentSourceTimeMs;
		const currentTimeSec = currentTimeMs / 1e3;
		const currentWord = transcriptionFragment.word_segments.find((word) => currentTimeSec >= word.start && currentTimeSec <= word.end);
		const currentSegment = transcriptionFragment.segments.find((segment) => currentTimeSec >= segment.start && currentTimeSec <= segment.end);
		for (const wordContainer of this.activeWordContainers) if (currentWord) {
			wordContainer.wordText = currentWord.text;
			wordContainer.wordStartMs = currentWord.start * 1e3;
			wordContainer.wordEndMs = currentWord.end * 1e3;
		}
		for (const segmentContainer of this.segmentContainers) if (currentSegment) {
			segmentContainer.segmentText = currentSegment.text;
			segmentContainer.segmentStartMs = currentSegment.start * 1e3;
			segmentContainer.segmentEndMs = currentSegment.end * 1e3;
		}
		if (currentWord && currentSegment) {
			const segmentWords = transcriptionFragment.word_segments.filter((word) => word.start >= currentSegment.start && word.end <= currentSegment.end);
			const currentWordIndex = segmentWords.findIndex((word) => word.start === currentWord.start && word.end === currentWord.end);
			if (currentWordIndex !== -1) {
				const beforeWords = segmentWords.slice(0, currentWordIndex).map((w) => w.text.trim()).join(" ");
				const afterWords = segmentWords.slice(currentWordIndex + 1).map((w) => w.text.trim()).join(" ");
				for (const container of this.beforeActiveWordContainers) {
					container.segmentText = beforeWords;
					container.segmentStartMs = currentSegment.start * 1e3;
					container.segmentEndMs = currentWord.start * 1e3;
				}
				for (const container of this.afterActiveWordContainers) {
					container.segmentText = afterWords;
					container.segmentStartMs = currentWord.end * 1e3;
					container.segmentEndMs = currentSegment.end * 1e3;
				}
			}
		}
	}
	get targetElement() {
		const target = document.getElementById(this.targetSelector ?? "");
		if (target instanceof EFAudio || target instanceof EFVideo) return target;
		throw new Error("Invalid target, must be an EFAudio or EFVideo element");
	}
};
_decorate([property({
	type: String,
	attribute: "display-mode",
	reflect: true
})], EFCaptions.prototype, "displayMode", void 0);
_decorate([property({
	type: Number,
	attribute: "context-words",
	reflect: true
})], EFCaptions.prototype, "contextWords", void 0);
_decorate([property({
	type: String,
	attribute: "target",
	reflect: true
})], EFCaptions.prototype, "targetSelector", void 0);
_decorate([property({ attribute: "word-style" })], EFCaptions.prototype, "wordStyle", void 0);
EFCaptions = _decorate([customElement("ef-captions")], EFCaptions);
export { EFCaptions, EFCaptionsActiveWord, EFCaptionsAfterActiveWord, EFCaptionsBeforeActiveWord, EFCaptionsSegment };
