import { IPublicClientApplication } from '@azure/msal-browser';
import { getAccessToken } from './authService';
import type {
    AgentReview, FlaggedItem, ResolvedItem, ErrorItem, PDFPage,
    KnowledgeBaseListItem, KnowledgeBaseDetail, SourceDocument,
    ProcessingJob, SpecVersionListItem, SpecVersionDetail, DiffResult,
} from '../types';

const API_URL = import.meta.env.VITE_BACKEND_URL || 'http://localhost:8000';

// Types for API responses
export interface CampaignResponse {
    id: string;
    name: string;
    workfront_id: string | null;
    client_lead: string | null;
    agency_lead: string | null;
    brand_guidelines: string | null;
    status: string;
    agency: string | null;
    created_by: string | null;
    created_at: string;
    updated_at: string;
    proofs: number;
}

export interface ProofVersionResponse {
    id: string;
    version: number;
    file_storage_key: string | null;
    thumbnail_url: string | null;
    agent_review: AgentReview | null;
    overall_status: string | null;
    workfront_id: string | null;
    is_identical_file: boolean | null;
    created_at: string;
}

export interface ProofResponse {
    id: string;
    proof_name: string;
    channel: string | null;
    sub_channel: string | null;
    proof_type: string | null;
    workfront_id: string | null;
    created_at: string;
    versions: ProofVersionResponse[];
}

export interface AnalyticsResponse {
    total_reviews: number;
    passed: number;
    failed: number;
    errors: number;
    legal_review: number;
}

export interface AgencyAnalyticsItem {
    agency_id: string;
    agency_name: string;
    total_reviews: number;
    passed: number;
    failed: number;
    errors: number;
    legal_review: number;
}

export interface AgencyAnalyticsResponse {
    agencies: AgencyAnalyticsItem[];
}

export interface FlaggedItemResponse {
    id: string;
    proof_version_id: string;
    agent_flagged: string;
    comments: string | null;
    submitter_name: string | null;
    submitter_agency: string | null;
    campaign_name: string | null;
    proof_name: string | null;
    version: number | null;
    created_at: string;
}

export interface ResolvedItemResponse {
    id: string;
    proof_version_id: string;
    agent: string;
    issue: string | null;
    resolution: string | null;
    submitter_name: string | null;
    submitter_agency: string | null;
    campaign_name: string | null;
    proof_name: string | null;
    version: number | null;
    created_at: string;
}

export interface ErrorItemResponse {
    id: string;
    proof_version_id: string;
    error_summary: string | null;
    submitter_name: string | null;
    submitter_agency: string | null;
    campaign_name: string | null;
    proof_name: string | null;
    version: number | null;
    created_at: string;
}

class ApiService {
    private msalInstance: IPublicClientApplication | null = null;

    setMsalInstance(instance: IPublicClientApplication) {
        this.msalInstance = instance;
    }

    private async getHeaders(): Promise<HeadersInit> {
        const headers: HeadersInit = {
            'Content-Type': 'application/json',
        };

        if (this.msalInstance) {
            const token = await getAccessToken(this.msalInstance);
            if (token) {
                headers['Authorization'] = `Bearer ${token}`;
            }
        }

        return headers;
    }

    private async fetch<T>(endpoint: string, options: RequestInit = {}): Promise<T> {
        const headers = await this.getHeaders();
        const response = await fetch(`${API_URL}/api${endpoint}`, {
            ...options,
            headers: {
                ...headers,
                ...options.headers,
            },
        });

        if (!response.ok) {
            const errorData = await response.json().catch(() => ({}));
            throw new Error(errorData.detail || `HTTP ${response.status}: ${response.statusText}`);
        }

        // Handle 204 No Content
        if (response.status === 204) {
            return undefined as T;
        }

        return response.json();
    }

    // Current user endpoint
    async getMe(): Promise<CurrentUserResponse> {
        return this.fetch<CurrentUserResponse>('/me');
    }

    // Campaign endpoints
    async getCampaigns(agencyId?: string): Promise<CampaignResponse[]> {
        const params = agencyId ? `?agency_id=${agencyId}` : '';
        return this.fetch<CampaignResponse[]>(`/campaigns${params}`);
    }

    async getCampaign(id: string): Promise<CampaignResponse> {
        return this.fetch<CampaignResponse>(`/campaigns/${id}`);
    }

    async createCampaign(data: {
        name: string;
        workfront_id?: string;
        client_lead?: string;
        agency_lead?: string;
        brand_guidelines?: string;
    }): Promise<CampaignResponse> {
        return this.fetch<CampaignResponse>('/campaigns', {
            method: 'POST',
            body: JSON.stringify(data),
        });
    }

    async updateCampaign(id: string, data: {
        name?: string;
        workfront_id?: string;
        client_lead?: string;
        agency_lead?: string;
        brand_guidelines?: string;
        status?: string;
    }): Promise<CampaignResponse> {
        return this.fetch<CampaignResponse>(`/campaigns/${id}`, {
            method: 'PUT',
            body: JSON.stringify(data),
        });
    }

    async deleteCampaign(id: string): Promise<void> {
        return this.fetch<void>(`/campaigns/${id}`, {
            method: 'DELETE',
        });
    }

    // Proof endpoints
    async getProofs(campaignId: string): Promise<ProofResponse[]> {
        return this.fetch<ProofResponse[]>(`/campaigns/${campaignId}/proofs`);
    }

    async getProof(id: string): Promise<ProofResponse> {
        return this.fetch<ProofResponse>(`/proofs/${id}`);
    }

    async getFile(storageKey: string): Promise<File> {
        const headers = await this.getHeaders();
        const response = await fetch(`${API_URL}/api/files/${storageKey}`, { headers });
        if (!response.ok) {
            throw new Error(`Failed to fetch file: HTTP ${response.status}`);
        }
        const blob = await response.blob();
        const filename = storageKey.split('/').pop() || 'proof';
        return new File([blob], filename, { type: blob.type });
    }

    async getPdfPages(storageKey: string, maxPages: number = 10): Promise<PDFPage[]> {
        const headers = await this.getHeaders();
        const response = await fetch(
            `${API_URL}/api/files/${storageKey}/pages?max_pages=${maxPages}`,
            { headers }
        );
        if (!response.ok) {
            throw new Error(`Failed to fetch PDF pages: HTTP ${response.status}`);
        }
        const data = await response.json();
        return data.pages as PDFPage[];
    }

    async deleteProof(id: string): Promise<void> {
        return this.fetch<void>(`/proofs/${id}`, {
            method: 'DELETE',
        });
    }

    // Audit endpoints
    async flagProofVersion(proofId: string, version: number, data: {
        agent_flagged: string;
        comments?: string;
    }): Promise<FlaggedItemResponse> {
        return this.fetch<FlaggedItemResponse>(`/proofs/${proofId}/versions/${version}/flag`, {
            method: 'POST',
            body: JSON.stringify(data),
        });
    }

    async resolveProofVersion(proofId: string, version: number, data: {
        agent: string;
        issue?: string;
        resolution?: string;
    }): Promise<ResolvedItemResponse> {
        return this.fetch<ResolvedItemResponse>(`/proofs/${proofId}/versions/${version}/resolve`, {
            method: 'POST',
            body: JSON.stringify(data),
        });
    }

    async getFlaggedItems(agencyId?: string): Promise<FlaggedItemResponse[]> {
        const params = agencyId ? `?agency_id=${agencyId}` : '';
        return this.fetch<FlaggedItemResponse[]>(`/audit/flagged${params}`);
    }

    async getResolvedItems(agencyId?: string): Promise<ResolvedItemResponse[]> {
        const params = agencyId ? `?agency_id=${agencyId}` : '';
        return this.fetch<ResolvedItemResponse[]>(`/audit/resolved${params}`);
    }

    async getErrorItems(agencyId?: string): Promise<ErrorItemResponse[]> {
        const params = agencyId ? `?agency_id=${agencyId}` : '';
        return this.fetch<ErrorItemResponse[]>(`/audit/errors${params}`);
    }

    // Analytics endpoints
    async getAnalytics(agencyId?: string): Promise<AnalyticsResponse> {
        const params = agencyId ? `?agency_id=${agencyId}` : '';
        return this.fetch<AnalyticsResponse>(`/analytics${params}`);
    }

    async getAnalyticsByAgency(): Promise<AgencyAnalyticsResponse> {
        return this.fetch<AgencyAnalyticsResponse>('/analytics/by-agency');
    }

    // Helper to convert API response to frontend format
    convertCampaignToFrontend(campaign: CampaignResponse) {
        return {
            name: campaign.name,
            workfrontId: campaign.workfront_id || '',
            clientLead: campaign.client_lead || '',
            agency: campaign.agency || '',
            agencyLead: campaign.agency_lead || '',
            proofs: campaign.proofs,
            status: campaign.status as 'In Progress' | 'Completed',
            lastModified: campaign.updated_at,
            brandGuidelines: campaign.brand_guidelines || 'Barclays',
            createdBy: campaign.created_by || null,
            _id: campaign.id,
        };
    }

    convertProofToFrontend(proof: ProofResponse) {
        const latestVersion = proof.versions[0];
        return {
            proofName: proof.proof_name,
            channel: proof.channel || '',
            subChannel: proof.sub_channel || '',
            proofType: proof.proof_type || '',
            status: latestVersion?.overall_status === 'Analysis Error' ? 'error' : 'completed' as 'completed' | 'analyzing' | 'error' | 'loading',
            overallStatus: latestVersion?.overall_status as any,
            versions: proof.versions.map(v => ({
                version: v.version,
                timestamp: v.created_at.split('T')[0],
                workfrontId: v.workfront_id || '',
                proofPreviewUrl: v.thumbnail_url || '',
                feedback: v.agent_review || {} as AgentReview,
                overallStatus: v.overall_status as any,
                fileStorageKey: v.file_storage_key || '',
                isIdenticalFile: v.is_identical_file || false,
            })),
            _id: proof.id,
            fileStorageKey: latestVersion?.file_storage_key || '',
        };
    }

    convertFlaggedItemToFrontend(item: FlaggedItemResponse): FlaggedItem {
        return {
            id: item.id,
            campaignName: item.campaign_name || '',
            proofName: item.proof_name || '',
            version: item.version || 1,
            submitter: item.submitter_name || '',
            submitAgency: item.submitter_agency || '',
            agentFlagged: item.agent_flagged,
            comments: item.comments || '',
            timestamp: item.created_at,
        };
    }

    convertResolvedItemToFrontend(item: ResolvedItemResponse): ResolvedItem {
        return {
            id: item.id,
            campaignName: item.campaign_name || '',
            proofName: item.proof_name || '',
            version: item.version || 1,
            submitter: item.submitter_name || '',
            submitAgency: item.submitter_agency || '',
            agent: item.agent,
            issue: item.issue || '',
            resolution: item.resolution || '',
            timestamp: item.created_at,
        };
    }

    convertErrorItemToFrontend(item: ErrorItemResponse): ErrorItem {
        return {
            id: item.id,
            campaignName: item.campaign_name || '',
            proofName: item.proof_name || '',
            version: item.version || 1,
            submitter: item.submitter_name || '',
            submitAgency: item.submitter_agency || '',
            errorSummary: item.error_summary || '',
            timestamp: item.created_at,
        };
    }

    // Dropdown options endpoints
    async getDropdownOptions(): Promise<DropdownOptionsResponse> {
        const response = await this.fetch<DropdownOptionsResponse>('/dropdown-options');
        // Debug logging
        console.log('[DEBUG API Response] Raw dropdown options:', JSON.stringify(response, null, 2));
        console.log('[DEBUG API Response] Social.Meta proof types:', response.channels?.Social?.Meta);
        return response;
    }

    async addChannel(name: string): Promise<void> {
        await this.fetch<void>(`/dropdown-options/channels?name=${encodeURIComponent(name)}`, {
            method: 'POST',
        });
    }

    async addSubChannel(channel: string, name: string): Promise<void> {
        await this.fetch<void>(`/dropdown-options/channels/${encodeURIComponent(channel)}/sub-channels?name=${encodeURIComponent(name)}`, {
            method: 'POST',
        });
    }

    async addProofType(channel: string, subChannel: string, name: string): Promise<void> {
        await this.fetch<void>(`/dropdown-options/channels/${encodeURIComponent(channel)}/sub-channels/${encodeURIComponent(subChannel)}/proof-types?name=${encodeURIComponent(name)}`, {
            method: 'POST',
        });
    }

    async deleteChannel(channel: string): Promise<void> {
        await this.fetch<void>(`/dropdown-options/channels/${encodeURIComponent(channel)}`, {
            method: 'DELETE',
        });
    }

    async deleteSubChannel(channel: string, subChannel: string): Promise<void> {
        await this.fetch<void>(`/dropdown-options/channels/${encodeURIComponent(channel)}/sub-channels/${encodeURIComponent(subChannel)}`, {
            method: 'DELETE',
        });
    }

    async deleteProofType(channel: string, subChannel: string, proofType: string): Promise<void> {
        await this.fetch<void>(`/dropdown-options/channels/${encodeURIComponent(channel)}/sub-channels/${encodeURIComponent(subChannel)}/proof-types/${encodeURIComponent(proofType)}`, {
            method: 'DELETE',
        });
    }

    // User management endpoints (super_admin only)
    async getUsers(): Promise<UserManagementResponse[]> {
        return this.fetch<UserManagementResponse[]>('/users');
    }

    async updateUser(userId: string, data: { role?: string; agency_id?: string | null }): Promise<UserManagementResponse> {
        return this.fetch<UserManagementResponse>(`/users/${userId}`, {
            method: 'PUT',
            body: JSON.stringify(data),
        });
    }

    async getUserChangeHistory(userId: string): Promise<UserChangeLogEntry[]> {
        return this.fetch<UserChangeLogEntry[]>(`/users/${userId}/change-history`);
    }

    async createAgency(name: string): Promise<AgencyResponse> {
        return this.fetch<AgencyResponse>('/agencies', {
            method: 'POST',
            body: JSON.stringify({ name }),
        });
    }

    // Agency endpoints
    async getAgencies(): Promise<AgencyResponse[]> {
        return this.fetch<AgencyResponse[]>('/agencies');
    }

    // Support email endpoint
    async sendSupportEmail(data: {
        message: string;
        subject: string;
        user_name?: string;
        user_email?: string;
    }): Promise<{ success: boolean; message: string }> {
        return this.fetch('/support/email', {
            method: 'POST',
            body: JSON.stringify(data),
        });
    }

    // Export endpoints
    async downloadCampaignsCsv(agencyId?: string): Promise<void> {
        const headers = await this.getHeaders();
        const params = agencyId ? `?agency_id=${agencyId}` : '';
        const response = await fetch(`${API_URL}/api/export/campaigns-csv${params}`, { headers });
        if (!response.ok) {
            const errorData = await response.json().catch(() => ({}));
            throw new Error(errorData.detail || `HTTP ${response.status}: ${response.statusText}`);
        }
        const blob = await response.blob();
        const url = URL.createObjectURL(blob);
        const a = document.createElement('a');
        a.href = url;
        const disposition = response.headers.get('Content-Disposition') || '';
        const match = disposition.match(/filename="([^"]+)"/);
        a.download = match ? match[1] : 'campaigns_export.csv';
        document.body.appendChild(a);
        a.click();
        document.body.removeChild(a);
        URL.revokeObjectURL(url);
    }

    // Knowledge Base endpoints
    async getKnowledgeBases(): Promise<KnowledgeBaseListItem[]> {
        return this.fetch<KnowledgeBaseListItem[]>('/knowledge-base');
    }

    async getKnowledgeBase(kbId: string): Promise<KnowledgeBaseDetail> {
        return this.fetch<KnowledgeBaseDetail>(`/knowledge-base/${kbId}`);
    }

    async uploadSourceDocument(kbId: string, file: File): Promise<SourceDocument> {
        const headers = await this.getHeaders();
        // Remove Content-Type so browser sets multipart boundary
        delete (headers as Record<string, string>)['Content-Type'];

        const formData = new FormData();
        formData.append('file', file);

        const response = await fetch(`${API_URL}/api/knowledge-base/${kbId}/documents`, {
            method: 'POST',
            headers,
            body: formData,
        });

        if (!response.ok) {
            const errorData = await response.json().catch(() => ({}));
            throw new Error(errorData.detail || `HTTP ${response.status}: ${response.statusText}`);
        }

        return response.json();
    }

    async removeSourceDocument(kbId: string, docId: string): Promise<void> {
        return this.fetch<void>(`/knowledge-base/${kbId}/documents/${docId}`, {
            method: 'DELETE',
        });
    }

    async triggerProcessing(kbId: string): Promise<ProcessingJob> {
        return this.fetch<ProcessingJob>(`/knowledge-base/${kbId}/process`, {
            method: 'POST',
        });
    }

    async getProcessingJob(kbId: string, jobId: string): Promise<ProcessingJob> {
        return this.fetch<ProcessingJob>(`/knowledge-base/${kbId}/jobs/${jobId}`);
    }

    async getSpecVersions(kbId: string): Promise<SpecVersionListItem[]> {
        return this.fetch<SpecVersionListItem[]>(`/knowledge-base/${kbId}/versions`);
    }

    async getSpecVersion(kbId: string, versionId: string): Promise<SpecVersionDetail> {
        return this.fetch<SpecVersionDetail>(`/knowledge-base/${kbId}/versions/${versionId}`);
    }

    async getSpecDiff(kbId: string, versionIdA: string, versionIdB: string): Promise<DiffResult> {
        return this.fetch<DiffResult>(`/knowledge-base/${kbId}/versions/${versionIdA}/diff/${versionIdB}`);
    }

    async activateSpecVersion(kbId: string, versionId: string): Promise<SpecVersionDetail> {
        return this.fetch<SpecVersionDetail>(`/knowledge-base/${kbId}/versions/${versionId}/activate`, {
            method: 'POST',
        });
    }
}

export interface DropdownOptionsResponse {
    campaigns: string[];
    channels: Record<string, Record<string, string[]>>;
    brand_guidelines: string[];
}

export interface AgencyResponse {
    id: string;
    name: string;
}

export interface CurrentUserResponse {
    id: string;
    email: string;
    name: string;
    role: string;
    agency_id: string | null;
    agency_name: string | null;
}

export interface UserManagementResponse {
    id: string;
    email: string;
    name: string;
    role: string;
    agency: string | null;
    agency_id: string | null;
    created_at: string;
}

export interface UserChangeLogEntry {
    id: string;
    change_type: string;
    field_changed: string | null;
    old_value: string | null;
    new_value: string | null;
    changed_by_name: string | null;
    created_at: string;
}

export const apiService = new ApiService();
export default apiService;
