import { API_BASE, state } from './state.js';
import { showToast } from './utils.js';

let _renderBinder = null;
let _updateBinderSelectors = null;

export function injectDependencies(renderBinderFn, updateBinderSelectorsFn) {
    _renderBinder = renderBinderFn;
    _updateBinderSelectors = updateBinderSelectorsFn;
}

export async function fetchTags() {
    try {
        const response = await fetch(`${API_BASE}/tags`);
        if (response.ok) {
            state.allTags = await response.json();
        }
    } catch (e) {
        console.error("Failed to fetch tags", e);
    }
}

export async function fetchSettings() {
    try {
        const response = await fetch(`${API_BASE}/settings`);
        if (response.ok) {
            state.settings = await response.json();
        }
    } catch (e) {
        console.error("Failed to fetch settings", e);
    }
}

export async function updateSettingsApi(partial) {
    const response = await fetch(`${API_BASE}/settings`, {
        method: 'PUT',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(partial)
    });
    if (!response.ok) throw new Error('設定の更新に失敗しました');
    const updated = await response.json();
    state.settings = updated;
    return updated;
}

export async function fetchBinderCards() {
    if (!state.currentBinder || !state.currentBinder.placements) {
        state.currentCards = [];
        return;
    }
    const cardIds = state.currentBinder.placements
        .filter(p => p.type === 'card')
        .map(p => p.id);
        
    if (cardIds.length === 0) {
        state.currentCards = [];
        return;
    }

    try {
        const response = await fetch(`${API_BASE}/cards?ids=${cardIds.join(',')}`);
        if (!response.ok) throw new Error('カードの取得に失敗しました');
        state.currentCards = await response.json();

        try {
            const locRes = await fetch(`${API_BASE}/cards/locations`, {
                method: 'POST',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify({ ids: cardIds })
            });
            if (locRes.ok) {
                const locations = await locRes.json();
                state.currentCards.forEach(r => {
                    r.locations = locations[r.id] || [];
                });
            }
        } catch (le) {
            console.error('Failed to fetch resource locations', le);
        }
    } catch (error) {
        console.error(error);
        state.currentCards = [];
    }
}

export async function syncAndRender() {
    await fetchBinderCards();
    if (_renderBinder) _renderBinder();
}

export async function fetchBinder(binderId) {
    if (window.App && window.App.cancelGravity) window.App.cancelGravity();
    try {
        const response = await fetch(`${API_BASE}/binderes/${binderId}`);
        if (!response.ok) throw new Error('バインダーの取得に失敗しました');
        const data = await response.json();
        state.currentBinder = data;
        
        localStorage.setItem('lorebinder_last_binder', binderId);
        
        await fetchBinderCards();
        if (_renderBinder) _renderBinder();
    } catch (error) {
        showToast(error.message, 'error');
        if (state.binderList.length > 0 && binderId !== state.binderList[0].id) {
            localStorage.removeItem('lorebinder_last_binder');
            await fetchBinder(state.binderList[0].id);
            if (_updateBinderSelectors) _updateBinderSelectors();
        }
    }
}

export async function fetchBinderList() {
    try {
        const response = await fetch(`${API_BASE}/binderes`);
        if (response.ok) {
            state.binderList = await response.json();
        }
    } catch (e) {
        console.error("Failed to fetch binderes", e);
    }
}

export async function savePlacements() {
    if (state.gravityLocked) return;
    if (!state.currentBinder) return;
    const cards = document.querySelectorAll('.binder-card, .binder-zone');
    const newPlacements = [];
    cards.forEach(c => {
        const id = c.dataset.id;
        const type = c.dataset.type || (c.classList.contains('binder-zone') ? 'zone' : 'card');
        const x = parseFloat(c.dataset.x || 0);
        const y = parseFloat(c.dataset.y || 0);
        if (id) {
            const placementData = {
                id: id,
                type: type,
                x: x,
                y: y,
                width: c.offsetWidth || 250,
                height: c.offsetHeight || 150
            };
            if (type === 'zone') {
                placementData.status = c.dataset.status;
            } else {
                placementData.pinned = c.dataset.pinned === 'true';
                placementData.rotation = parseFloat(c.dataset.rotation || 0);
            }
            newPlacements.push(placementData);
        }
    });
    
    state.currentBinder.placements = newPlacements;

    const listIndex = state.binderList.findIndex(b => b.id === state.currentBinder.id);
    if (listIndex !== -1) {
        state.binderList[listIndex].placements = newPlacements;
    }

    try {
        await fetch(`${API_BASE}/binderes/${state.currentBinder.id}/placements`, {
            method: 'PUT',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify({ placements: newPlacements })
        });
    } catch (error) {
        console.error("Failed to save placements", error);
    }
}

export async function updateBinderInfo(title, description) {
    if (!state.currentBinder) return;
    try {
        const response = await fetch(`${API_BASE}/binderes/${state.currentBinder.id}`, {
            method: 'PUT',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify({ title, description })
        });
        if (!response.ok) throw new Error('バインダー情報の更新に失敗しました');
        const updated = await response.json();
        state.currentBinder.title = updated.title;
        state.currentBinder.description = updated.description;
        
        const listIndex = state.binderList.findIndex(c => c.id === state.currentBinder.id);
        if (listIndex !== -1) {
            state.binderList[listIndex].title = updated.title;
            state.binderList[listIndex].description = updated.description;
        }

        if (_updateBinderSelectors) _updateBinderSelectors();
        showToast('バインダー情報を更新しました', 'success');
    } catch (error) {
        showToast(error.message, 'error');
    }
}

export async function saveViewport(scale, translateX, translateY) {
    if (!state.currentBinder) return;
    try {
        await fetch(`${API_BASE}/binderes/${state.currentBinder.id}`, {
            method: 'PUT',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify({ scale, translateX, translateY })
        });
        state.currentBinder.scale = scale;
        state.currentBinder.translateX = translateX;
        state.currentBinder.translateY = translateY;
    } catch (error) {
        console.error('Failed to save viewport', error);
    }
}

export async function toggleBinderPinApi(binderId, pinned) {
    const response = await fetch(`${API_BASE}/binderes/${binderId}`, {
        method: 'PUT',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ pinned })
    });
    if (!response.ok) throw new Error('ピン留め状態の更新に失敗しました');
    const updated = await response.json();

    const listIndex = state.binderList.findIndex(c => c.id === binderId);
    if (listIndex !== -1) {
        state.binderList[listIndex].pinned = updated.pinned;
    }
    if (state.currentBinder && state.currentBinder.id === binderId) {
        state.currentBinder.pinned = updated.pinned;
    }

    return updated.pinned;
}

export async function saveResourceApi({ id, title, content, tags }) {
    const payload = { title, content, tags };
    const method = id ? 'PUT' : 'POST';
    const url = id ? `${API_BASE}/cards/${id}` : `${API_BASE}/cards`;

    const response = await fetch(url, {
        method: method,
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(payload)
    });

    if (!response.ok) throw new Error('保存に失敗しました');

    let savedData = {};
    if (response.headers.get('content-type')?.includes('application/json')) {
        savedData = await response.json();
    }
    return { savedData, isNew: !id };
}

export async function openExplorer(path) {
    const response = await fetch(`${API_BASE}/file/open-explorer`, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ path })
    });

    if (!response.ok) {
        let errorMsg = 'エクスプローラを開けませんでした';
        try {
            const errorData = await response.json();
            const err = errorData && errorData.error;
            if (err) {
                errorMsg = typeof err === 'string' ? err : (err.message || errorMsg);
            }
        } catch (e) {}
        throw new Error(errorMsg);
    }
}
