// Questo file fa parte di MyTown.
// MyTown è software libero: puoi ridistribuirlo e/o modificarlo secondo
// i termini della GNU Affero General Public License come pubblicata dalla
// Free Software Foundation, versione 3.
// Distribuito senza ALCUNA GARANZIA; vedi la GNU AGPL v3 per i dettagli.
// Copyright (C) Kondor Consulting & Services S.r.l.
// SPDX-License-Identifier: AGPL-3.0-or-later

import { Component } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { ConfigService } from '../../../providers/config.service';
import { LayoutService } from '../../../providers/layout.service';
import { FileDownloadService } from '../../../providers/fileDownload.service';
import { WorkflowService } from '../../../providers/workflow.service';
import { WfActivity, WfCampo, WfSnapshot, WfSnapshotFile, WfUploadedFile } from '../../../models/workflow.model';

/** Campo mostrato (read-only) nel dettaglio di uno step. */
interface StepField {
	label: string;
	type: number;
	value: string;
	files: WfUploadedFile[]; // type 8
	isNote: boolean; // type 9
	open?: boolean; // nota: aperta/chiusa
}

/** Riga della timeline dello storico (un job dell'istanza). */
interface TimelineStep {
	wfj_id: string;
	label: string;
	description?: string;
	date?: string;
	done: boolean; // wfj_state === 1
	expanded: boolean;
	fields: StepField[];
	snapshot: WfSnapshot | null;
}

@Component({
	selector: 'app-workflow-detail',
	templateUrl: './workflow-detail.page.html',
	styleUrls: ['./workflow-detail.page.scss'],
	standalone: false,
})
export class WorkflowDetailPage {
	wfin_id = '';
	cmp_id = 0;
	prt_id = 0;
	title = '';
	loading = false;
	steps: TimelineStep[] = [];

	constructor(
		private route: ActivatedRoute,
		private config: ConfigService,
		public layout: LayoutService,
		private wf: WorkflowService,
		private fileDownload: FileDownloadService,
	) {}

	ionViewWillEnter() {
		this.wfin_id = this.route.snapshot.paramMap.get('wfin_id') || '';
		this.resolveIds();
		// titolo passato dalla lista (wf_name), fallback al numero istanza
		const navTitle = (history.state && history.state.title) || '';
		this.title = navTitle || 'Istanza #' + this.wfin_id;
		this.layout.setPageConfig({
			title: 'Storico workflow',
			showBack: true,
			backButtonHref: `/portale/${this.prt_id}/company/${this.cmp_id}/service/workflow`,
		});
		this.load();
	}

	private resolveIds() {
		let r: ActivatedRoute | null = this.route;
		while (r) {
			const pm = r.snapshot.paramMap;
			if (pm.get('cmp_id')) this.cmp_id = +(pm.get('cmp_id') as string);
			if (pm.get('prt_id')) this.prt_id = +(pm.get('prt_id') as string);
			r = r.parent;
		}
	}

	load(ev?: any) {
		if (!this.wfin_id) return;
		this.loading = true;
		this.wf.getInstanceDetail(this.wfin_id).subscribe({
			next: (data) => {
				if (data?.wf_name || data?.wfin_description) {
					this.title = (data.wf_name as string) || (data.wfin_description as string);
				}
				// ordino per data (più recente in alto); a parità, il job aperto (in corso) sopra
				const jobs = (data?.jobs || []).slice().sort((a, b) => {
					const da = a.wfj_dateins || '';
					const db = b.wfj_dateins || '';
					if (da !== db) return da < db ? 1 : -1; // decrescente
					return (a.wfj_state ?? 0) - (b.wfj_state ?? 0); // a parità: aperto (0) prima
				});
				this.steps = jobs.map((j) => {
					const { activity, snapshot } = this.wf.parseJob(j);
					return {
						wfj_id: j.wfj_id,
						label: activity?.label || j.wfj_description || j.wfj_detail || 'Attività',
						description: j.wfj_description,
						date: j.wfj_dateins,
						done: j.wfj_state === 1,
						expanded: false,
						fields: this.buildFields(activity),
						snapshot,
					};
				});
				this.loading = false;
				ev?.target?.complete();
			},
			error: (e) => {
				this.config.presentToastError(typeof e === 'string' ? e : 'Errore nel caricamento dello storico');
				this.loading = false;
				ev?.target?.complete();
			},
		});
	}

	toggle(s: TimelineStep) {
		s.expanded = !s.expanded;
	}

	hasDetails(s: TimelineStep): boolean {
		return s.fields.length > 0 || !!s.snapshot;
	}

	/** Estrae i campi mostrabili (con valore) dall'attività del job. */
	private buildFields(activity: WfActivity | null): StepField[] {
		if (!activity) return [];
		const out: StepField[] = [];
		const pushCampi = (campi?: WfCampo[]) => {
			for (const f of campi || []) {
				if (f.visible === false) continue;
				if (f.settings && f.type !== 9) continue;
				const files = f.type === 8 ? f.file || [] : [];
				const value = this.displayValue(f);
				// salta i campi senza alcun contenuto (tranne note e file)
				if (f.type !== 9 && files.length === 0 && !value) continue;
				out.push({ label: f.label, type: f.type, value, files, isNote: f.type === 9 });
			}
		};
		pushCampi(activity.campi);
		for (const c of activity.components || []) {
			if ((c.cm_module_name || '').toLowerCase().startsWith('button')) continue;
			pushCampi(c.campi);
		}
		return out;
	}

	private displayValue(f: WfCampo): string {
		if (f.type === 7) {
			const list = f.value_list || [];
			return list.map((v) => this.optionText(f, v)).join(', ');
		}
		if (f.type === 3) return this.optionText(f, f.value);
		return f.value || '';
	}

	private optionText(f: WfCampo, val: any): string {
		const opt = (f.option || []).find((o) => String(o.value) === String(val));
		return opt ? opt.text : String(val ?? '');
	}

	// ─── file ──────────────────────────────────────────────────────
	/** Allegato caricato in un campo (type 8): aperto via repositoryName. */
	openUploaded(file: WfUploadedFile) {
		const url = this.wf.uploadedFileUrl(file.repositoryName);
		if (!url) {
			this.config.presentToastError('File non disponibile');
			return;
		}
		this.fileDownload.downloadAndOpenFile(url, file.fileOrigName || 'file');
	}

	/** File dello snapshot (entità web): aperto via drfl_id documentale. */
	openSnapshotFile(f: WfSnapshotFile) {
		if (!f?.drfl_id) return;
		this.wf.getFileDownloadUrl(f.drfl_id).subscribe({
			next: (url) => {
				if (!url) {
					this.config.presentToastError('File non disponibile');
					return;
				}
				this.fileDownload.downloadAndOpenFile(url, f.filename || 'file', f.mime);
			},
			error: () => this.config.presentToastError('Errore download del file'),
		});
	}

	fileIcon(name?: string, mime?: string): string {
		return this.config.getFileIcon(name || '', mime);
	}
}
