import { Client } from '@notionhq/client';

export interface NotionDatabase {
    id: string;
    title: string;
    selected: boolean;
    dateProperty?: string; // name of the date property to use
}

export interface NotionEvent {
    id: string;
    title: string;
    description?: string;
    start: string; // ISO date or datetime
    end?: string;
    allDay: boolean;
    url?: string;
    databaseId: string;
    databaseTitle: string;
}

/**
 * Find all databases shared with the integration
 */
export async function getUserDatabases(accessToken: string): Promise<NotionDatabase[]> {
    const notion = new Client({ auth: accessToken });

    const response = await notion.search({
        filter: { property: 'object', value: 'database' },
        page_size: 50,
    });

    const databases: NotionDatabase[] = [];
    for (const result of response.results) {
        if (result.object !== 'database') continue;
        const db = result as any;
        const title = db.title?.map((t: any) => t.plain_text).join('') || 'Untitled';

        // Find a date property in the database schema
        let dateProperty: string | undefined;
        if (db.properties) {
            for (const [name, prop] of Object.entries(db.properties)) {
                if ((prop as any).type === 'date') {
                    dateProperty = name;
                    break;
                }
            }
        }

        databases.push({
            id: db.id,
            title,
            selected: true,
            dateProperty,
        });
    }

    return databases;
}

/**
 * Query a Notion database for items with dates in the given range
 */
export async function getUpcomingEvents(
    accessToken: string,
    databaseId: string,
    dateProperty: string,
    timeMin: string,
    timeMax: string,
    databaseTitle: string,
): Promise<NotionEvent[]> {
    const notion = new Client({ auth: accessToken });

    const startDate = timeMin.split('T')[0];
    const endDate = timeMax.split('T')[0];

    let results: any[] = [];
    let hasMore = true;
    let startCursor: string | undefined;

    while (hasMore) {
        const response = await notion.databases.query({
            database_id: databaseId,
            filter: {
                and: [
                    {
                        property: dateProperty,
                        date: { on_or_after: startDate },
                    },
                    {
                        property: dateProperty,
                        date: { on_or_before: endDate },
                    },
                ],
            },
            start_cursor: startCursor,
            page_size: 100,
        });

        results = results.concat(response.results);
        hasMore = response.has_more;
        startCursor = response.next_cursor || undefined;
    }

    return results.map((page: any) => {
        // Extract title from the first title property
        let title = 'Untitled';
        for (const [, prop] of Object.entries(page.properties)) {
            const p = prop as any;
            if (p.type === 'title' && p.title?.length > 0) {
                title = p.title.map((t: any) => t.plain_text).join('');
                break;
            }
        }

        // Extract date
        const dateProp = page.properties[dateProperty];
        const dateVal = dateProp?.date;
        const start = dateVal?.start || '';
        const end = dateVal?.end || undefined;
        const allDay = start.length === 10; // YYYY-MM-DD = all day

        return {
            id: page.id,
            title,
            description: undefined,
            start,
            end,
            allDay,
            url: page.url,
            databaseId,
            databaseTitle,
        };
    });
}

/**
 * Create a page in a Notion database
 */
export async function createEvent(
    accessToken: string,
    databaseId: string,
    dateProperty: string,
    title: string,
    startDate: string,
    endDate?: string,
): Promise<string> {
    const notion = new Client({ auth: accessToken });

    const page = await notion.pages.create({
        parent: { database_id: databaseId },
        properties: {
            // The title property - find it dynamically
            title: {
                title: [{ text: { content: title } }],
            },
            [dateProperty]: {
                date: {
                    start: startDate,
                    end: endDate || null,
                },
            },
        } as any,
    });

    return page.id;
}

/**
 * Update a page in Notion
 */
export async function updateEvent(
    accessToken: string,
    pageId: string,
    dateProperty: string,
    title?: string,
    startDate?: string,
    endDate?: string,
): Promise<void> {
    const notion = new Client({ auth: accessToken });

    const properties: any = {};
    if (title !== undefined) {
        properties.title = { title: [{ text: { content: title } }] };
    }
    if (startDate !== undefined) {
        properties[dateProperty] = {
            date: { start: startDate, end: endDate || null },
        };
    }

    await notion.pages.update({
        page_id: pageId,
        properties,
    });
}

/**
 * Archive (soft-delete) a page in Notion
 */
export async function deleteEvent(
    accessToken: string,
    pageId: string,
): Promise<void> {
    const notion = new Client({ auth: accessToken });

    await notion.pages.update({
        page_id: pageId,
        archived: true,
    });
}

/**
 * Refresh Notion OAuth token
 */
export async function refreshAccessToken(
    refreshToken: string,
    clientId: string,
    clientSecret: string,
): Promise<{ accessToken: string; refreshToken: string; expiresAt?: Date }> {
    const credentials = Buffer.from(`${clientId}:${clientSecret}`).toString('base64');

    const response = await fetch('https://api.notion.com/v1/oauth/token', {
        method: 'POST',
        headers: {
            'Authorization': `Basic ${credentials}`,
            'Content-Type': 'application/json',
        },
        body: JSON.stringify({
            grant_type: 'refresh_token',
            refresh_token: refreshToken,
        }),
    });

    if (!response.ok) {
        const error = await response.text();
        throw new Error(`Notion token refresh failed: ${error}`);
    }

    const data = await response.json();
    return {
        accessToken: data.access_token,
        refreshToken: data.refresh_token || refreshToken,
        expiresAt: undefined, // Notion doesn't return expiry in refresh
    };
}
