/**
 * POST /publish-post
 * 
 * Features:
 * - Hashtag extraction and storage
 * - AI tone analysis
 * - Rate limiting via trust state
 * - Beacon support (location-based alerts)
 */

import { serve } from 'https://deno.land/std@0.177.0/http/server.ts';
import { createSupabaseClient, createServiceClient } from '../_shared/supabase-client.ts';
import { validatePostBody, validateUUID, ValidationError } from '../_shared/validation.ts';
import { trySignR2Url } from '../_shared/r2_signer.ts';

interface PublishPostRequest {
  category_id?: string | null;
  body: string;
  body_format?: 'plain' | 'markdown';
  allow_chain?: boolean;
  chain_parent_id?: string | null;
  chain_parent_id?: string | null;
  image_url?: string | null;
  thumbnail_url?: string | null;
  ttl_hours?: number | null;
  user_warned?: boolean;

  // Beacon fields (optional)
  is_beacon?: boolean;
  beacon_type?: 'police' | 'checkpoint' | 'taskForce' | 'hazard' | 'safety' | 'community';
  beacon_lat?: number;
  beacon_long?: number;
}

interface AnalysisResult {
  flagged: boolean;
  category?: 'bigotry' | 'nsfw' | 'violence';
  flags: string[];
  rejectReason?: string;
}

const ALLOWED_ORIGIN = Deno.env.get('ALLOWED_ORIGIN') || '*';
const CORS_HEADERS = {
  'Access-Control-Allow-Origin': ALLOWED_ORIGIN,
  'Access-Control-Allow-Methods': 'POST',
  'Access-Control-Allow-Headers': 'authorization, x-client-info, apikey, content-type',
};

type ModerationStatus = 'approved' | 'flagged_bigotry' | 'flagged_nsfw' | 'rejected';

function getModerationStatus(category?: AnalysisResult['category']): ModerationStatus {
  switch (category) {
    case 'bigotry':
      return 'flagged_bigotry';
    case 'nsfw':
      return 'flagged_nsfw';
    case 'violence':
      return 'rejected';
    default:
      return 'approved';
  }
}

/**
 * Extract hashtags from post body using regex
 * Returns array of lowercase tags without the # prefix
 */
function extractHashtags(body: string): string[] {
  const hashtagRegex = /#\w+/g;
  const matches = body.match(hashtagRegex);
  if (!matches) return [];

  // Remove # prefix and lowercase all tags
  return [...new Set(matches.map(tag => tag.substring(1).toLowerCase()))];
}

serve(async (req: Request) => {
  // CORS preflight
  if (req.method === 'OPTIONS') {
    return new Response(null, { headers: CORS_HEADERS });
  }

  try {
    // 1. Validate auth
    const authHeader = req.headers.get('Authorization');
    if (!authHeader) {
      return new Response(JSON.stringify({ error: 'Missing authorization header' }), {
        status: 401,
        headers: { ...CORS_HEADERS, 'Content-Type': 'application/json' },
      });
    }

    const supabase = createSupabaseClient(authHeader);
    const {
      data: { user },
      error: authError,
    } = await supabase.auth.getUser();

    if (authError || !user) {
      console.error('Auth error details:', {
        error: authError,
        errorMessage: authError?.message,
        errorStatus: authError?.status,
        user: user,
        authHeader: authHeader ? 'present' : 'missing',
      });
      return new Response(JSON.stringify({
        error: 'Unauthorized',
        details: authError?.message,
      }), {
        status: 401,
        headers: { ...CORS_HEADERS, 'Content-Type': 'application/json' },
      });
    }

    const { data: profileRows, error: profileError } = await supabase
      .from('profiles')
      .select('id')
      .eq('id', user.id)
      .limit(1);

    if (profileError) {
      console.error('Error checking profile:', profileError);
      return new Response(JSON.stringify({ error: 'Failed to verify profile' }), {
        status: 500,
        headers: { ...CORS_HEADERS, 'Content-Type': 'application/json' },
      });
    }

    if (!profileRows || profileRows.length === 0) {
      return new Response(
        JSON.stringify({
          error: 'Profile not found',
          message: 'Please complete your profile before posting.',
        }),
        {
          status: 400,
          headers: { ...CORS_HEADERS, 'Content-Type': 'application/json' },
        }
      );
    }

    // 2. Parse request
    const {
      category_id,
      body,
      body_format,
      allow_chain,
      chain_parent_id,
      image_url,
      thumbnail_url,
      ttl_hours,
      user_warned,
      is_beacon,
      beacon_type,
      beacon_lat,
      beacon_long,
    } = (await req.json()) as PublishPostRequest;
    const requestedCategoryId = category_id ?? null;

    // 3. Validate inputs
    // For beacons, category_id is ignored and replaced by "Beacon Alerts" internally
    validatePostBody(body);
    if (is_beacon !== true && category_id) {
      validateUUID(category_id, 'category_id');
    }
    if (chain_parent_id) {
      validateUUID(chain_parent_id, 'chain_parent_id');
    }

    let ttlHours: number | null | undefined = undefined;
    if (ttl_hours !== undefined && ttl_hours !== null) {
      const parsedTtl = Number(ttl_hours);
      if (!Number.isFinite(parsedTtl) || !Number.isInteger(parsedTtl) || parsedTtl < 0) {
        return new Response(
          JSON.stringify({
            error: 'Validation error',
            message: 'ttl_hours must be a non-negative integer',
          }),
          {
            status: 400,
            headers: { ...CORS_HEADERS, 'Content-Type': 'application/json' },
          }
        );
      }
      ttlHours = parsedTtl;
    }

    // Validate beacon fields if provided
    if (is_beacon === true) {
      const latMissing = beacon_lat === undefined || beacon_lat === null || Number.isNaN(beacon_lat);
      const longMissing = beacon_long === undefined || beacon_long === null || Number.isNaN(beacon_long);

      if (latMissing || longMissing) {
        return new Response(
          JSON.stringify({
            error: 'Validation error',
            message: 'beacon_lat and beacon_long are required for beacon posts',
          }),
          {
            status: 400,
            headers: { ...CORS_HEADERS, 'Content-Type': 'application/json' },
          }
        );
      }

      const validBeaconTypes = ['police', 'checkpoint', 'taskForce', 'hazard', 'safety', 'community'];
      if (beacon_type && !validBeaconTypes.includes(beacon_type)) {
        return new Response(
          JSON.stringify({
            error: 'Validation error',
            message: 'Invalid beacon_type. Must be: police, checkpoint, taskForce, hazard, safety, or community',
          }),
          {
            status: 400,
            headers: { ...CORS_HEADERS, 'Content-Type': 'application/json' },
          }
        );
      }
    }

    // 4. Check if user can post (rate limiting via trust state)
    const serviceClient = createServiceClient();
    const { data: canPostData, error: canPostError } = await serviceClient.rpc('can_post', {
      p_user_id: user.id,
    });

    if (canPostError) {
      console.error('Error checking post eligibility:', canPostError);
      return new Response(JSON.stringify({ error: 'Failed to check posting eligibility' }), {
        status: 500,
        headers: { ...CORS_HEADERS, 'Content-Type': 'application/json' },
      });
    }

    if (!canPostData) {
      const { data: limitData } = await serviceClient.rpc('get_post_rate_limit', {
        p_user_id: user.id,
      });

      return new Response(
        JSON.stringify({
          error: 'Rate limit reached',
          message: `You have reached your posting limit for today (${limitData} posts).`,
          suggestion: 'Take a moment. Your influence grows with patience.',
        }),
        {
          status: 429,
          headers: { ...CORS_HEADERS, 'Content-Type': 'application/json' },
        }
      );
    }

    // 5. Validate chain parent (if any)
    if (chain_parent_id) {
      const { data: parentPost, error: parentError } = await supabase
        .from('posts')
        .select('id, allow_chain, status')
        .eq('id', chain_parent_id)
        .single();

      if (parentError || !parentPost) {
        return new Response(
          JSON.stringify({
            error: 'Chain unavailable',
            message: 'This post is not available for chaining.',
          }),
          {
            status: 400,
            headers: { ...CORS_HEADERS, 'Content-Type': 'application/json' },
          }
        );
      }

      if (!parentPost.allow_chain || parentPost.status !== 'active') {
        return new Response(
          JSON.stringify({
            error: 'Chain unavailable',
            message: 'Chaining has been disabled for this post.',
          }),
          {
            status: 400,
            headers: { ...CORS_HEADERS, 'Content-Type': 'application/json' },
          }
        );
      }
    }

    // 6. Call tone-check function for AI moderation
    let analysis: AnalysisResult = {
      flagged: false,
      category: undefined,
      flags: [],
      rejectReason: undefined,
    };

    try {
      const supabaseUrl = Deno.env.get('SUPABASE_URL') || '';
      const supabaseKey = Deno.env.get('SUPABASE_ANON_KEY') || '';

      console.log('Calling tone-check function...');

      const moderationResponse = await fetch(
        `${supabaseUrl}/functions/v1/tone-check`,
        {
          method: 'POST',
          headers: {
            'Authorization': `Bearer ${authHeader}`,
            'Content-Type': 'application/json',
            'apikey': supabaseKey,
          },
          body: JSON.stringify({
            text: body,
            imageUrl: image_url || undefined,
          }),
        }
      );

      console.log('tone-check response status:', moderationResponse.status);

      if (moderationResponse.ok) {
        const data = await moderationResponse.json();
        console.log('tone-check response:', JSON.stringify(data));

        const flagged = Boolean(data.flagged);
        const category = data.category as AnalysisResult['category'] | undefined;

        analysis = {
          flagged,
          category,
          flags: data.flags || [],
          rejectReason: data.reason,
        };

        console.log('Analysis result:', JSON.stringify(analysis));
      } else {
        console.error('tone-check failed:', await moderationResponse.text());
      }
    } catch (e) {
      console.error('Tone check error:', e);
      // Fail CLOSED: Reject post if moderation is unavailable
      await serviceClient.rpc('log_audit_event', {
        p_actor_id: user.id,
        p_event_type: 'post_rejected_moderation_error',
        p_payload: {
          category_id: requestedCategoryId,
          error: e.toString(),
        },
      });

      return new Response(
        JSON.stringify({
          error: 'Moderation unavailable',
          message: 'Content moderation is temporarily unavailable. Please try again later.',
        }),
        {
          status: 503,
          headers: { ...CORS_HEADERS, 'Content-Type': 'application/json' },
        }
      );
    }

    // 7. Reject hostile or hateful content
    if (analysis.flagged) {
      const moderationStatus = getModerationStatus(analysis.category);
      if (user_warned === true) {
        const { data: profileRow } = await serviceClient
          .from('profiles')
          .select('strikes')
          .eq('id', user.id)
          .maybeSingle();
        const currentStrikes = typeof profileRow?.strikes === 'number' ? profileRow!.strikes : 0;

        await serviceClient
          .from('profiles')
          .update({ strikes: currentStrikes + 1 })
          .eq('id', user.id);
      }

      await serviceClient.rpc('log_audit_event', {
        p_actor_id: user.id,
        p_event_type: 'post_rejected',
        p_payload: {
          category_id: requestedCategoryId,
          moderation_category: analysis.category,
          flags: analysis.flags,
          reason: analysis.rejectReason,
          moderation_status: moderationStatus,
          user_warned: user_warned === true,
        },
      });

      return new Response(
        JSON.stringify({
          error: 'Content rejected',
          message: analysis.rejectReason || 'This content was rejected by moderation.',
          category: analysis.category,
          moderation_status: moderationStatus,
        }),
        {
          status: 400,
          headers: { ...CORS_HEADERS, 'Content-Type': 'application/json' },
        }
      );
    }

    // 8. Determine post status based on tone
    const status = 'active';
    const moderationStatus: ModerationStatus = 'approved';
    const toneLabel = 'neutral';
    const cisScore = 0.8;

    // 9. Extract hashtags from body (skip for beacons - they use description as body)
    const tags = is_beacon === true ? [] : extractHashtags(body);
    console.log(`Extracted ${tags.length} tags:`, tags);

    // 10. Handle beacon category and data
    let postCategoryId = requestedCategoryId;
    let beaconData: any = null;

    if (is_beacon === true) {
      // Get or create "Beacon Alerts" category for beacons
      const { data: beaconCategory } = await serviceClient
        .from('categories')
        .select('id')
        .eq('name', 'Beacon Alerts')
        .single();

      if (beaconCategory) {
        postCategoryId = beaconCategory.id;
      } else {
        // Create the beacon category if it doesn't exist
        const { data: newCategory } = await serviceClient
          .from('categories')
          .insert({ name: 'Beacon Alerts', description: 'Community safety and alert posts' })
          .select('id')
          .single();

        if (newCategory) {
          postCategoryId = newCategory.id;
        }
      }

      // Get user's trust score for initial confidence
      const { data: profile } = await serviceClient
        .from('profiles')
        .select('trust_state(harmony_score)')
        .eq('id', user.id)
        .single();

      const trustScore = profile?.trust_state?.harmony_score ?? 0.5;
      const initialConfidence = 0.5 + (trustScore * 0.3);

      // Store beacon data to be included in post
      beaconData = {
        is_beacon: true,
        beacon_type: beacon_type ?? 'community',
        location: `SRID=4326;POINT(${beacon_long} ${beacon_lat})`,
        confidence_score: Math.min(1.0, Math.max(0.0, initialConfidence)),
        is_active_beacon: true,
        allow_chain: false, // Beacons don't allow chaining
      };
    }

    // 11. Resolve post expiration
    let expiresAt: string | null = null;
    if (ttlHours !== undefined) {
      if (ttlHours > 0) {
        expiresAt = new Date(Date.now() + ttlHours * 60 * 60 * 1000).toISOString();
      } else {
        expiresAt = null;
      }
    } else {
      const { data: settingsRow, error: settingsError } = await supabase
        .from('user_settings')
        .select('default_post_ttl')
        .eq('user_id', user.id)
        .maybeSingle();

      if (settingsError) {
        console.error('Error fetching user settings:', settingsError);
      } else {
        const defaultTtl = settingsRow?.default_post_ttl;
        if (typeof defaultTtl === 'number' && defaultTtl > 0) {
          expiresAt = new Date(Date.now() + defaultTtl * 60 * 60 * 1000).toISOString();
        }
      }
    }

    // 12. Create post with tags and beacon data
    let postVisibility = 'public';
    const { data: privacyRow, error: privacyError } = await supabase
      .from('profile_privacy_settings')
      .select('posts_visibility')
      .eq('user_id', user.id)
      .maybeSingle();

    if (privacyError) {
      console.error('Error fetching privacy settings:', privacyError);
    } else if (privacyRow?.posts_visibility) {
      postVisibility = privacyRow.posts_visibility;
    }

    const insertData: any = {
      author_id: user.id,
      category_id: postCategoryId ?? null,
      body,
      body_format: body_format ?? 'plain',
      tone_label: toneLabel,
      cis_score: cisScore,
      status,
      moderation_status: moderationStatus,
      allow_chain: beaconData?.allow_chain ?? (allow_chain ?? true),
      chain_parent_id: chain_parent_id ?? null,
      image_url: image_url ?? null,
      thumbnail_url: thumbnail_url ?? null,
      tags: tags,
      expires_at: expiresAt,
      visibility: postVisibility,
    };

    // Add beacon fields if this is a beacon
    if (beaconData) {
      insertData.is_beacon = beaconData.is_beacon;
      insertData.beacon_type = beaconData.beacon_type;
      insertData.location = beaconData.location;
      insertData.confidence_score = beaconData.confidence_score;
      insertData.is_active_beacon = beaconData.is_active_beacon;
    }

    // Use service client for INSERT to bypass RLS issues for private users
    // The user authentication has already been validated above
    const { data: post, error: postError } = await serviceClient
      .from('posts')
      .insert(insertData)
      .select()
      .single();

    if (postError) {
      console.error('Error creating post:', JSON.stringify({
        code: postError.code,
        message: postError.message,
        details: postError.details,
        hint: postError.hint,
        user_id: user.id,
      }));
      return new Response(JSON.stringify({ error: 'Failed to create post', details: postError.message }), {
        status: 500,
        headers: { ...CORS_HEADERS, 'Content-Type': 'application/json' },
      });
    }

    // 13. Log successful post
    await serviceClient.rpc('log_audit_event', {
      p_actor_id: user.id,
      p_event_type: 'post_created',
      p_payload: {
        post_id: post.id,
        category_id: postCategoryId,
        tone: toneLabel,
        cis: cisScore,
        chain_parent_id: chain_parent_id ?? null,
        tags_count: tags.length,
        is_beacon: is_beacon ?? false,
      },
    });

    // 14. Return post with metadata - FLATTENED STRUCTURE
    let message = 'Your post is ready.';
    if (toneLabel === 'negative' || toneLabel === 'mixed') {
      message = 'This post may have limited reach based on its tone.';
    }

    // Create a flattened post object that merges post data with location data
    const flattenedPost: any = {
      ...post,
      // Add location fields at the top level for beacons
      ...(beaconData && {
        latitude: beacon_lat,
        longitude: beacon_long,
      }),
    };

    if (flattenedPost.image_url) {
      flattenedPost.image_url = await trySignR2Url(flattenedPost.image_url);
    }
    if (flattenedPost.thumbnail_url) {
      flattenedPost.thumbnail_url = await trySignR2Url(flattenedPost.thumbnail_url);
    }

    const response: any = {
      post: flattenedPost,
      tone_analysis: {
        tone: toneLabel,
        cis: cisScore,
        message,
      },
      tags,
    };

    return new Response(
      JSON.stringify(response),
      {
        status: 201,
        headers: { ...CORS_HEADERS, 'Content-Type': 'application/json' },
      }
    );
  } catch (error) {
    if (error instanceof ValidationError) {
      return new Response(
        JSON.stringify({
          error: 'Validation error',
          message: error.message,
          field: error.field,
        }),
        {
          status: 400,
          headers: { ...CORS_HEADERS, 'Content-Type': 'application/json' },
        }
      );
    }

    console.error('Unexpected error:', error);
    return new Response(JSON.stringify({ error: 'Internal server error' }), {
      status: 500,
      headers: { ...CORS_HEADERS, 'Content-Type': 'application/json' },
    });
  }
});
