import type { ResultSetHeader, RowDataPacket } from 'mysql2';
import type {
	KategoriWarung,
	ModeInventori,
	Warung,
	WarungFormInput,
	WarungPublic
} from '$lib/types/warung';
import db from '$lib/server/db';
import { getGoogleMapsUrl, slugify } from '$lib/utils/slug';

interface WarungRow extends RowDataPacket {
	id: number;
	member_id: number;
	nama: string;
	slug: string;
	deskripsi: string | null;
	kategori: KategoriWarung;
	alamat: string;
	kelurahan: string | null;
	kecamatan: string | null;
	kota: string | null;
	provinsi: string | null;
	kode_pos: string | null;
	telepon: string | null;
	whatsapp: string | null;
	latitude: string | number;
	longitude: string | number;
	jam_buka: string;
	jam_tutup: string;
	hari_buka: string;
	foto_url: string | null;
	is_aktif: number;
	is_publik: number;
	mode_inventori: ModeInventori;
	created_at: Date;
	updated_at: Date;
	nama_pemilik?: string;
}

function toNumber(value: unknown): number {
	return Number(value ?? 0);
}

function toBool(value: unknown): boolean {
	return value === 1 || value === true || value === '1';
}

function mapWarung(row: WarungRow): Warung {
	return {
		id: row.id,
		member_id: row.member_id,
		nama: row.nama,
		slug: row.slug,
		deskripsi: row.deskripsi ?? '',
		kategori: row.kategori,
		alamat: row.alamat,
		kelurahan: row.kelurahan ?? '',
		kecamatan: row.kecamatan ?? '',
		kota: row.kota ?? '',
		provinsi: row.provinsi ?? '',
		kode_pos: row.kode_pos ?? '',
		telepon: row.telepon ?? '',
		whatsapp: row.whatsapp ?? '',
		latitude: toNumber(row.latitude),
		longitude: toNumber(row.longitude),
		jam_buka: row.jam_buka?.slice(0, 5) ?? '08:00',
		jam_tutup: row.jam_tutup?.slice(0, 5) ?? '21:00',
		hari_buka: row.hari_buka ?? 'Senin-Minggu',
		foto_url: row.foto_url ?? '',
		is_aktif: toBool(row.is_aktif),
		is_publik: toBool(row.is_publik),
		mode_inventori: row.mode_inventori ?? 'tanpa_stok',
		created_at: new Date(row.created_at).toISOString(),
		updated_at: new Date(row.updated_at).toISOString()
	};
}

function mapWarungPublic(row: WarungRow): WarungPublic {
	const warung = mapWarung(row);
	return {
		id: warung.id,
		nama: warung.nama,
		slug: warung.slug,
		deskripsi: warung.deskripsi,
		kategori: warung.kategori,
		alamat: warung.alamat,
		kelurahan: warung.kelurahan,
		kecamatan: warung.kecamatan,
		kota: warung.kota,
		provinsi: warung.provinsi,
		telepon: warung.telepon,
		whatsapp: warung.whatsapp,
		latitude: warung.latitude,
		longitude: warung.longitude,
		jam_buka: warung.jam_buka,
		jam_tutup: warung.jam_tutup,
		hari_buka: warung.hari_buka,
		foto_url: warung.foto_url,
		google_maps_url: getGoogleMapsUrl(warung.latitude, warung.longitude),
		nama_pemilik: row.nama_pemilik ?? ''
	};
}

async function generateUniqueSlug(nama: string, memberId: number): Promise<string> {
	const base = slugify(nama) || `warung-${memberId}`;
	let slug = base;
	let counter = 1;

	while (true) {
		const [rows] = await db.query<RowDataPacket[]>(
			'SELECT id FROM warung WHERE slug = ? AND member_id != ? LIMIT 1',
			[slug, memberId]
		);
		if (rows.length === 0) return slug;
		slug = `${base}-${counter++}`;
	}
}

export async function getWarungByMemberId(memberId: number): Promise<Warung | null> {
	const [rows] = await db.query<WarungRow[]>(
		'SELECT * FROM warung WHERE member_id = ? LIMIT 1',
		[memberId]
	);

	return rows[0] ? mapWarung(rows[0]) : null;
}

export async function upsertWarung(memberId: number, input: WarungFormInput): Promise<number> {
	const slug = await generateUniqueSlug(input.nama, memberId);
	const existing = await getWarungByMemberId(memberId);

	const values = [
		input.nama,
		slug,
		input.deskripsi,
		input.kategori,
		input.alamat,
		input.kelurahan,
		input.kecamatan,
		input.kota,
		input.provinsi,
		input.kode_pos,
		input.telepon,
		input.whatsapp,
		toNumber(input.latitude),
		toNumber(input.longitude),
		input.jam_buka,
		input.jam_tutup,
		input.hari_buka,
		input.foto_url || null,
		input.is_aktif ? 1 : 0,
		input.is_publik ? 1 : 0,
		input.mode_inventori
	];

	if (existing) {
		const [result] = await db.query<ResultSetHeader>(
			`
			UPDATE warung SET
				nama = ?, slug = ?, deskripsi = ?, kategori = ?, alamat = ?,
				kelurahan = ?, kecamatan = ?, kota = ?, provinsi = ?, kode_pos = ?,
				telepon = ?, whatsapp = ?, latitude = ?, longitude = ?,
				jam_buka = ?, jam_tutup = ?, hari_buka = ?, foto_url = ?,
				is_aktif = ?, is_publik = ?, mode_inventori = ?
			WHERE member_id = ?
			`,
			[...values, memberId]
		);
		return result.affectedRows > 0 ? existing.id : existing.id;
	}

	const [result] = await db.query<ResultSetHeader>(
		`
		INSERT INTO warung (
			member_id, nama, slug, deskripsi, kategori, alamat,
			kelurahan, kecamatan, kota, provinsi, kode_pos,
			telepon, whatsapp, latitude, longitude,
			jam_buka, jam_tutup, hari_buka, foto_url, is_aktif, is_publik, mode_inventori
		) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
		`,
		[memberId, ...values]
	);

	return result.insertId;
}

export interface WarungSearchParams {
	q?: string;
	kota?: string;
	kategori?: KategoriWarung;
}

export async function getPublicWarungs(params: WarungSearchParams = {}): Promise<WarungPublic[]> {
	const conditions = ['w.is_publik = 1', 'w.is_aktif = 1'];
	const queryParams: (string | number)[] = [];

	if (params.kota) {
		conditions.push('w.kota LIKE ?');
		queryParams.push(`%${params.kota}%`);
	}

	if (params.kategori) {
		conditions.push('w.kategori = ?');
		queryParams.push(params.kategori);
	}

	if (params.q) {
		conditions.push('(w.nama LIKE ? OR w.deskripsi LIKE ? OR w.alamat LIKE ? OR w.kelurahan LIKE ?)');
		const term = `%${params.q}%`;
		queryParams.push(term, term, term, term);
	}

	const [rows] = await db.query<WarungRow[]>(
		`
		SELECT w.*, m.nama AS nama_pemilik
		FROM warung w
		INNER JOIN member m ON m.id = w.member_id
		WHERE ${conditions.join(' AND ')}
		ORDER BY w.nama ASC
		`,
		queryParams
	);

	return rows.map(mapWarungPublic);
}

export async function getPublicWarungBySlug(slug: string): Promise<WarungPublic | null> {
	const [rows] = await db.query<WarungRow[]>(
		`
		SELECT w.*, m.nama AS nama_pemilik
		FROM warung w
		INNER JOIN member m ON m.id = w.member_id
		WHERE w.slug = ? AND w.is_publik = 1 AND w.is_aktif = 1
		LIMIT 1
		`,
		[slug]
	);

	return rows[0] ? mapWarungPublic(rows[0]) : null;
}

export function warungToFormInput(warung: Warung | null): WarungFormInput {
	if (!warung) {
		return {
			nama: '',
			deskripsi: '',
			kategori: 'campuran',
			alamat: '',
			kelurahan: '',
			kecamatan: '',
			kota: '',
			provinsi: '',
			kode_pos: '',
			telepon: '',
			whatsapp: '',
			latitude: '',
			longitude: '',
			jam_buka: '08:00',
			jam_tutup: '21:00',
			hari_buka: 'Senin-Minggu',
			hari_buka_kode: 'senin-minggu',
			kodepos_id: '',
			foto_url: '',
			is_aktif: true,
			is_publik: true,
			mode_inventori: 'tanpa_stok'
		};
	}

	return {
		nama: warung.nama,
		deskripsi: warung.deskripsi,
		kategori: warung.kategori,
		alamat: warung.alamat,
		kelurahan: warung.kelurahan,
		kecamatan: warung.kecamatan,
		kota: warung.kota,
		provinsi: warung.provinsi,
		kode_pos: warung.kode_pos,
		telepon: warung.telepon,
		whatsapp: warung.whatsapp,
		latitude: warung.latitude ? String(warung.latitude) : '',
		longitude: warung.longitude ? String(warung.longitude) : '',
		jam_buka: warung.jam_buka,
		jam_tutup: warung.jam_tutup,
		hari_buka: warung.hari_buka,
		hari_buka_kode: '',
		kodepos_id: '',
		foto_url: warung.foto_url,
		is_aktif: warung.is_aktif,
		is_publik: warung.is_publik,
		mode_inventori: warung.mode_inventori
	};
}

export async function pakaiStokInventori(memberId: number): Promise<boolean> {
	const { getMemberEntitlements, hasPrivilege } = await import('$lib/server/langganan');
	const warung = await getWarungByMemberId(memberId);
	const entitlements = await getMemberEntitlements(memberId);
	return warung?.mode_inventori === 'dengan_stok' && hasPrivilege(entitlements, 'inventori_stok');
}
